From e151cba02dadef827b965690c296918367c8fdcd Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Thu, 1 Oct 2026 01:31:25 +0200 Subject: [PATCH] JIT: remove unused shared helpers Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4119d093-350c-4187-aa05-c7779793e89f --- src/coreclr/jit/codegen.h | 9 +- src/coreclr/jit/codegencommon.cpp | 145 ------- src/coreclr/jit/codegenlinear.cpp | 127 ------ src/coreclr/jit/compiler.cpp | 88 ---- src/coreclr/jit/compiler.h | 16 - src/coreclr/jit/fgprofilesynthesis.cpp | 87 ---- src/coreclr/jit/fgprofilesynthesis.h | 4 - src/coreclr/jit/hashbv.cpp | 366 +---------------- src/coreclr/jit/hashbv.h | 34 +- src/coreclr/jit/jiteh.cpp | 540 +------------------------ src/coreclr/jit/layout.cpp | 107 +---- src/coreclr/jit/utils.cpp | 271 ------------- src/coreclr/jit/utils.h | 18 - 13 files changed, 16 insertions(+), 1796 deletions(-) diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h index 93b53362e05a70..41e96fd2e808a7 100644 --- a/src/coreclr/jit/codegen.h +++ b/src/coreclr/jit/codegen.h @@ -674,10 +674,7 @@ class CodeGen final : public CodeGenInterface // //------------------------------------------------------------------------- - void genSinglePush(); - void genSinglePop(); - regMaskTP genPushRegs(regMaskTP regs, regMaskTP* byrefRegs, regMaskTP* noRefRegs); - void genPopRegs(regMaskTP regs, regMaskTP byrefRegs, regMaskTP noRefRegs); + void genSinglePush(); /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @@ -1163,10 +1160,6 @@ class CodeGen final : public CodeGenInterface void genTransferRegGCState(regNumber dst, regNumber src); void genConsumeAddress(GenTree* addr); void genConsumeAddrMode(GenTreeAddrMode* mode); - void genSetBlockSize(GenTreeBlk* blkNode, regNumber sizeReg); - void genConsumeBlockSrc(GenTreeBlk* blkNode); - void genSetBlockSrc(GenTreeBlk* blkNode, regNumber srcReg); - void genConsumeBlockOp(GenTreeBlk* blkNode, regNumber dstReg, regNumber srcReg, regNumber sizeReg); void genConsumePutStructArgStk(GenTreePutArgStk* putArgStkNode, regNumber dstReg, diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 85e4ba2f45d1ee..4eac08e6cd7c63 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -6410,151 +6410,6 @@ void CodeGen::genSinglePush() AddStackLevel(REGSIZE_BYTES); } -//------------------------------------------------------------------------ -// genSinglePop: Report a change in stack level caused by a single word-sized pop instruction -// -void CodeGen::genSinglePop() -{ - SubtractStackLevel(REGSIZE_BYTES); -} - -//------------------------------------------------------------------------ -// genPushRegs: Push the given registers. -// -// Arguments: -// regs - mask or registers to push -// byrefRegs - OUT arg. Set to byref registers that were pushed. -// noRefRegs - OUT arg. Set to non-GC ref registers that were pushed. -// -// Return Value: -// Mask of registers pushed. -// -// Notes: -// This function does not check if the register is marked as used, etc. -// -regMaskTP CodeGen::genPushRegs(regMaskTP regs, regMaskTP* byrefRegs, regMaskTP* noRefRegs) -{ - *byrefRegs = RBM_NONE; - *noRefRegs = RBM_NONE; - - if (regs == RBM_NONE) - { - return RBM_NONE; - } - -#if FEATURE_FIXED_OUT_ARGS - - NYI("Don't call genPushRegs with real regs!"); - return RBM_NONE; - -#else // FEATURE_FIXED_OUT_ARGS - - noway_assert(genTypeStSz(TYP_REF) == genTypeStSz(TYP_I_IMPL)); - noway_assert(genTypeStSz(TYP_BYREF) == genTypeStSz(TYP_I_IMPL)); - - regMaskTP pushedRegs = regs; - for (regNumber reg = REG_INT_FIRST; reg <= get_REG_INT_LAST(); reg = REG_NEXT(reg)) - { - regMaskTP regMask = genRegMask(reg); - - if ((regMask & pushedRegs) == RBM_NONE) - continue; - - var_types type; - if (regMask & gcInfo.gcRegGCrefSetCur) - { - type = TYP_REF; - } - else if (regMask & gcInfo.gcRegByrefSetCur) - { - *byrefRegs |= regMask; - type = TYP_BYREF; - } - else if (noRefRegs != NULL) - { - *noRefRegs |= regMask; - type = TYP_I_IMPL; - } - else - { - continue; - } - - inst_RV(INS_push, reg, type); - - genSinglePush(); - gcInfo.gcMarkRegSetNpt(regMask); - } - - return pushedRegs; - -#endif // FEATURE_FIXED_OUT_ARGS -} - -//------------------------------------------------------------------------ -// genPopRegs: Pop the registers that were pushed by genPushRegs(). -// -// Arguments: -// regs - mask of registers to pop -// byrefRegs - The byref registers that were pushed by genPushRegs(). -// noRefRegs - The non-GC ref registers that were pushed by genPushRegs(). -// -// Return Value: -// None -// -void CodeGen::genPopRegs(regMaskTP regs, regMaskTP byrefRegs, regMaskTP noRefRegs) -{ - if (regs == RBM_NONE) - { - return; - } - -#if FEATURE_FIXED_OUT_ARGS - - NYI("Don't call genPopRegs with real regs!"); - -#else // FEATURE_FIXED_OUT_ARGS - - noway_assert((regs & byrefRegs) == byrefRegs); - noway_assert((regs & noRefRegs) == noRefRegs); - noway_assert((regs & (gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur)) == RBM_NONE); - - noway_assert(genTypeStSz(TYP_REF) == genTypeStSz(TYP_INT)); - noway_assert(genTypeStSz(TYP_BYREF) == genTypeStSz(TYP_INT)); - - regMaskTP popedRegs = regs; - - // Walk the registers in the reverse order as genPushRegs() - for (regNumber reg = get_REG_INT_LAST(); reg >= REG_INT_FIRST; reg = REG_PREV(reg)) - { - regMaskTP regMask = genRegMask(reg); - - if ((regMask & popedRegs) == RBM_NONE) - continue; - - var_types type; - if (regMask & byrefRegs) - { - type = TYP_BYREF; - } - else if (regMask & noRefRegs) - { - type = TYP_INT; - } - else - { - type = TYP_REF; - } - - inst_RV(INS_pop, reg, type); - genSinglePop(); - - if (type != TYP_INT) - gcInfo.gcMarkRegPtrVal(reg, type); - } - -#endif // FEATURE_FIXED_OUT_ARGS -} #endif // !TARGET_WASM #ifdef DEBUG diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp index f866893b560bf0..46b0eab6acc8c2 100644 --- a/src/coreclr/jit/codegenlinear.cpp +++ b/src/coreclr/jit/codegenlinear.cpp @@ -1985,133 +1985,6 @@ void CodeGen::genPutArgStkFieldList(GenTreePutArgStk* putArgStk, unsigned outArg } #endif // !TARGET_X86 -//------------------------------------------------------------------------ -// genSetBlockSize: Ensure that the block size is in the given register -// -// Arguments: -// blkNode - The block node -// sizeReg - The register into which the block's size should go -// - -void CodeGen::genSetBlockSize(GenTreeBlk* blkNode, regNumber sizeReg) -{ - if (sizeReg != REG_NA) - { - assert((internalRegisters.GetAll(blkNode) & genRegMask(sizeReg)) != 0); - // This can go via helper which takes the size as a native uint. - instGen_Set_Reg_To_Imm(EA_PTRSIZE, sizeReg, blkNode->Size()); - } -} - -//------------------------------------------------------------------------ -// genConsumeBlockSrc: Consume the source address register of a block node, if any. -// -// Arguments: -// blkNode - The block node - -void CodeGen::genConsumeBlockSrc(GenTreeBlk* blkNode) -{ - GenTree* src = blkNode->Data(); - if (blkNode->OperIsCopyBlkOp()) - { - // For a CopyBlk we need the address of the source. - assert(src->isContained()); - if (src->OperIs(GT_IND)) - { - src = src->AsOp()->gtOp1; - } - else - { - // This must be a local. - // For this case, there is no source address register, as it is a - // stack-based address. - assert(src->OperIsLocal()); - return; - } - } - else - { - if (src->OperIsInitVal()) - { - src = src->gtGetOp1(); - } - } - genConsumeReg(src); -} - -//------------------------------------------------------------------------ -// genSetBlockSrc: Ensure that the block source is in its allocated register. -// -// Arguments: -// blkNode - The block node -// srcReg - The register in which to set the source (address or init val). -// -void CodeGen::genSetBlockSrc(GenTreeBlk* blkNode, regNumber srcReg) -{ - GenTree* src = blkNode->Data(); - if (blkNode->OperIsCopyBlkOp()) - { - // For a CopyBlk we need the address of the source. - if (src->OperIs(GT_IND)) - { - src = src->AsOp()->gtOp1; - } - else - { - // This must be a local struct. - // Load its address into srcReg. - unsigned varNum = src->AsLclVarCommon()->GetLclNum(); - unsigned offset = src->AsLclVarCommon()->GetLclOffs(); - GetEmitter()->emitIns_R_S(INS_lea, EA_BYREF, srcReg, varNum, offset); - return; - } - } - else - { - if (src->OperIsInitVal()) - { - src = src->gtGetOp1(); - } - } - genCopyRegIfNeeded(src, srcReg); -} - -//------------------------------------------------------------------------ -// genConsumeBlockOp: Ensure that the block's operands are enregistered -// as needed. -// Arguments: -// blkNode - The block node -// -// Notes: -// This ensures that the operands are consumed in the proper order to -// obey liveness modeling. - -void CodeGen::genConsumeBlockOp(GenTreeBlk* blkNode, regNumber dstReg, regNumber srcReg, regNumber sizeReg) -{ - // We have to consume the registers, and perform any copies, in the actual execution order: dst, src, size. - // - // Note that the register allocator ensures that the registers ON THE NODES will not interfere - // with one another if consumed (i.e. reloaded or moved to their ASSIGNED reg) in execution order. - // Further, it ensures that they will not interfere with one another if they are then copied - // to the REQUIRED register (if a fixed register requirement) in execution order. This requires, - // then, that we first consume all the operands, then do any necessary moves. - - GenTree* const dstAddr = blkNode->Addr(); - - // First, consume all the sources in order, and verify that registers have been allocated appropriately, - // based on the 'gtBlkOpKind'. - - // The destination is always in a register; 'genConsumeReg' asserts that. - genConsumeReg(dstAddr); - // The source may be a local or in a register; 'genConsumeBlockSrc' will check that. - genConsumeBlockSrc(blkNode); - - // Next, perform any necessary moves. - genCopyRegIfNeeded(dstAddr, dstReg); - genSetBlockSrc(blkNode, srcReg); - genSetBlockSize(blkNode, sizeReg); -} - //------------------------------------------------------------------------- // genSpillLocal: Generate the actual spill of a local var. // diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index c5edde4fdd4e7e..f532f0bb8acb34 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -7440,94 +7440,6 @@ VarScopeDsc* Compiler::compGetNextExitScope(unsigned offs, bool scan) return nullptr; } -// The function will call the callback functions for scopes with boundaries -// at instrs from the current status of the scope lists to 'offset', -// ordered by instrs. - -void Compiler::compProcessScopesUntil(unsigned offset, - VARSET_TP* inScope, - void (Compiler::*enterScopeFn)(VARSET_TP* inScope, VarScopeDsc*), - void (Compiler::*exitScopeFn)(VARSET_TP* inScope, VarScopeDsc*)) -{ - assert(offset != BAD_IL_OFFSET); - assert(inScope != nullptr); - - bool foundExit = false, foundEnter = true; - VarScopeDsc* scope; - VarScopeDsc* nextExitScope = nullptr; - VarScopeDsc* nextEnterScope = nullptr; - unsigned offs = offset, curEnterOffs = 0; - - goto START_FINDING_SCOPES; - - // We need to determine the scopes which are open for the current block. - // This loop walks over the missing blocks between the current and the - // previous block, keeping the enter and exit offsets in lockstep. - - do - { - foundExit = foundEnter = false; - - if (nextExitScope) - { - (this->*exitScopeFn)(inScope, nextExitScope); - nextExitScope = nullptr; - foundExit = true; - } - - offs = nextEnterScope ? nextEnterScope->vsdLifeBeg : offset; - - while ((scope = compGetNextExitScope(offs, true)) != nullptr) - { - foundExit = true; - - if (!nextEnterScope || scope->vsdLifeEnd > nextEnterScope->vsdLifeBeg) - { - // We overshot the last found Enter scope. Save the scope for later - // and find an entering scope - - nextExitScope = scope; - break; - } - - (this->*exitScopeFn)(inScope, scope); - } - - if (nextEnterScope) - { - (this->*enterScopeFn)(inScope, nextEnterScope); - curEnterOffs = nextEnterScope->vsdLifeBeg; - nextEnterScope = nullptr; - foundEnter = true; - } - - offs = nextExitScope ? nextExitScope->vsdLifeEnd : offset; - - START_FINDING_SCOPES: - - while ((scope = compGetNextEnterScope(offs, true)) != nullptr) - { - foundEnter = true; - - if ((nextExitScope && scope->vsdLifeBeg >= nextExitScope->vsdLifeEnd) || (scope->vsdLifeBeg > curEnterOffs)) - { - // We overshot the last found exit scope. Save the scope for later - // and find an exiting scope - - nextEnterScope = scope; - break; - } - - (this->*enterScopeFn)(inScope, scope); - - if (!nextExitScope) - { - curEnterOffs = scope->vsdLifeBeg; - } - } - } while (foundExit || foundEnter); -} - #if defined(DEBUG) void Compiler::compDispScopeLists() diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 9108251b4d7b01..aef0906800ff0d 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3263,11 +3263,9 @@ class Compiler // empty BB's when necessary: // * No block is both the first block of a handler and the first block of a try. // * No block is the first block of multiple 'try' regions. - // * No block is the last block of multiple EH regions. void fgNormalizeEH(); bool fgNormalizeEHCase1(); bool fgNormalizeEHCase2(); - bool fgNormalizeEHCase3(); bool fgCreateFiltersForGenericExceptions(); @@ -12213,20 +12211,11 @@ class Compiler class ClassLayoutTable* typGetClassLayoutTable(); public: - // Get the layout having the specified layout number. - ClassLayout* typGetLayoutByNum(unsigned layoutNum); - // Get the layout number of the specified layout. - unsigned typGetLayoutNum(ClassLayout* layout); // Get the layout for the specified class handle. ClassLayout* typGetObjLayout(CORINFO_CLASS_HANDLE classHandle); - // Get the number of a layout for the specified class handle. - unsigned typGetObjLayoutNum(CORINFO_CLASS_HANDLE classHandle); ClassLayout* typGetCustomLayout(const ClassLayoutBuilder& builder); - unsigned typGetCustomLayoutNum(const ClassLayoutBuilder& builder); // Get the layout having the specified size but no class handle. ClassLayout* typGetBlkLayout(unsigned blockSize); - // Get the number of a layout having the specified size but no class handle. - unsigned typGetBlkLayoutNum(unsigned blockSize); // Get the layout for the specified array of known length ClassLayout* typGetArrayLayout(CORINFO_CLASS_HANDLE classHandle, unsigned length); @@ -12487,11 +12476,6 @@ class Compiler VarScopeDsc* compGetNextExitScope(unsigned offs, bool scan = false); - void compProcessScopesUntil(unsigned offset, - VARSET_TP* inScope, - void (Compiler::*enterScopeFn)(VARSET_TP* inScope, VarScopeDsc*), - void (Compiler::*exitScopeFn)(VARSET_TP* inScope, VarScopeDsc*)); - #ifdef DEBUG void compDispScopeLists(); #endif // DEBUG diff --git a/src/coreclr/jit/fgprofilesynthesis.cpp b/src/coreclr/jit/fgprofilesynthesis.cpp index 038e571865b413..d45ddd96ae9493 100644 --- a/src/coreclr/jit/fgprofilesynthesis.cpp +++ b/src/coreclr/jit/fgprofilesynthesis.cpp @@ -152,14 +152,6 @@ void ProfileSynthesis::Run(ProfileSynthesisOption option) AssignLikelihoods(); break; - case ProfileSynthesisOption::ReverseLikelihoods: - ReverseLikelihoods(); - break; - - case ProfileSynthesisOption::RandomLikelihoods: - RandomizeLikelihoods(); - break; - case ProfileSynthesisOption::RepairLikelihoods: RepairLikelihoods(); break; @@ -773,85 +765,6 @@ void ProfileSynthesis::ClearLikelihoods() } } -//------------------------------------------------------------------------ -// ReverseLikelihoods: for all blocks, reverse likelihoods on all edges -// from the block -// -void ProfileSynthesis::ReverseLikelihoods() -{ -#ifdef DEBUG - JITDUMP("Reversing likelihoods\n"); - WeightVector likelihoods(m_comp->getAllocator(CMK_Pgo)); - for (BasicBlock* const block : m_comp->Blocks()) - { - SumOutgoingLikelihoods(block, &likelihoods); - - if (likelihoods.size() < 2) - { - continue; - } - - for (size_t i = 0; i < likelihoods.size() / 2; i++) - { - size_t j = likelihoods.size() - i - 1; - weight_t t = likelihoods[i]; - likelihoods[i] = likelihoods[j]; - likelihoods[j] = t; - } - - size_t k = 0; - for (FlowEdge* const succEdge : block->SuccEdges()) - { - succEdge->setLikelihood(likelihoods[k++]); - } - } -#endif // DEBUG -} - -//------------------------------------------------------------------------ -// RandomizeLikelihoods: for all blocks, randomize likelihoods on all edges -// from the block -// -// Notes: -// total outgoing likelihood for each block remains at 1.0 -// -void ProfileSynthesis::RandomizeLikelihoods() -{ -#ifdef DEBUG - // todo: external seed - JITDUMP("Randomizing likelihoods\n"); - WeightVector likelihoods(m_comp->getAllocator(CMK_Pgo)); - CLRRandom random; - - random.Init(m_comp->info.compMethodHash()); - - for (BasicBlock* const block : m_comp->Blocks()) - { - unsigned const N = block->NumSucc(); - likelihoods.clear(); - likelihoods.resize(N, 0); - - weight_t sum = 0; - unsigned i = 0; - - // Consider: something other than uniform distribution. - // As is, this will rarely set likelihoods to zero. - // - for (i = 0; i < N; i++) - { - likelihoods[i] = (weight_t)random.NextDouble(); - sum += likelihoods[i]; - } - - i = 0; - for (FlowEdge* const succEdge : block->SuccEdges()) - { - succEdge->setLikelihood(likelihoods[i++] / sum); - } - } -#endif // DEBUG -} - //------------------------------------------------------------------------ // FindCyclicProbabilities: for each loop, compute how much flow returns // to the loop head given one external count. diff --git a/src/coreclr/jit/fgprofilesynthesis.h b/src/coreclr/jit/fgprofilesynthesis.h index d34783a19525f1..4617c35929a4a8 100644 --- a/src/coreclr/jit/fgprofilesynthesis.h +++ b/src/coreclr/jit/fgprofilesynthesis.h @@ -21,8 +21,6 @@ enum class ProfileSynthesisOption RepairLikelihoods, BlendLikelihoods, ResetAndSynthesize, - ReverseLikelihoods, - RandomLikelihoods, }; //------------------------------------------------------------------------ @@ -93,8 +91,6 @@ class ProfileSynthesis void RepairLikelihoods(); void BlendLikelihoods(); void ClearLikelihoods(); - void ReverseLikelihoods(); - void RandomizeLikelihoods(); void ComputeCyclicProbabilities(); void ComputeCyclicProbabilities(FlowGraphNaturalLoop* loop); diff --git a/src/coreclr/jit/hashbv.cpp b/src/coreclr/jit/hashbv.cpp index d4f2467a036f0c..db531d5b6716ae 100644 --- a/src/coreclr/jit/hashbv.cpp +++ b/src/coreclr/jit/hashbv.cpp @@ -130,18 +130,6 @@ int hashBvNode::countBits() return result; } -bool hashBvNode::anyBits() -{ - for (int i = 0; i < this->numElements(); i++) - { - if (elements[i]) - { - return true; - } - } - return false; -} - bool hashBvNode::getBit(indexType base) { assert(base >= baseIndex); @@ -310,24 +298,6 @@ void hashBvNode::Subtract(hashBvNode* other) } } -bool hashBvNode::sameAs(hashBvNode* other) -{ - if (this->baseIndex != other->baseIndex) - { - return false; - } - - for (int i = 0; i < this->numElements(); i++) - { - if (this->elements[i] != other->elements[i]) - { - return false; - } - } - - return true; -} - // -------------------------------------------------------------------- // -------------------------------------------------------------------- @@ -348,21 +318,9 @@ hashBv::hashBv(Compiler* comp) hashBv* hashBv::Create(Compiler* compiler) { - hashBv* result; - hashBvGlobalData* gd = &compiler->hbvGlobalData; - - if (hbvFreeList(gd)) - { - result = hbvFreeList(gd); - hbvFreeList(gd) = result->next; - assert(result->nodeArr); - } - else - { - result = new (compiler, CMK_hashBv) hashBv(compiler); - memset((void*)result, 0, sizeof(hashBv)); - result->nodeArr = result->initialVector; - } + hashBv* result = new (compiler, CMK_hashBv) hashBv(compiler); + memset((void*)result, 0, sizeof(hashBv)); + result->nodeArr = result->initialVector; result->m_compiler = compiler; result->log2_hashSize = 0; @@ -390,56 +348,6 @@ hashBvNode** hashBv::getNewVector(int vectorLength) return newVector; } -hashBvNode*& hashBv::nodeFreeList(hashBvGlobalData* data) -{ - return data->hbvNodeFreeList; -} - -hashBv*& hashBv::hbvFreeList(hashBvGlobalData* data) -{ - return data->hbvFreeList; -} - -void hashBv::hbvFree() -{ - int hts = hashtable_size(); - for (int i = 0; i < hts; i++) - { - while (nodeArr[i]) - { - hashBvNode* curr = nodeArr[i]; - nodeArr[i] = curr->next; - curr->freeNode(globalData()); - } - } - // keep the vector attached because the whole thing is freelisted - // plus you don't even know if it's freeable - - this->next = hbvFreeList(globalData()); - hbvFreeList(globalData()) = this; -} - -hashBv* hashBv::CreateFrom(hashBv* other, Compiler* comp) -{ - hashBv* result = hashBv::Create(comp); - result->copyFrom(other, comp); - return result; -} - -void hashBv::MergeLists(hashBvNode** root1, hashBvNode** root2) -{ -} - -bool hashBv::TooSmall() -{ - return this->numNodes > this->hashtable_size() * 4; -} - -bool hashBv::TooBig() -{ - return this->hashtable_size() > this->numNodes * 4; -} - int hashBv::getNodeCount() { int size = hashtable_size(); @@ -645,21 +553,6 @@ void hashBv::dumpFancy() } #endif // DEBUG -void hashBv::removeNodeAtBase(indexType index) -{ - hashBvNode** insertionPoint = this->getInsertionPointForIndex(index); - - hashBvNode* node = *insertionPoint; - - // make sure that we were called to remove something - // that really was there - assert(node); - - // splice it out - *insertionPoint = node->next; - this->numNodes--; -} - int hashBv::getHashForIndex(indexType index, int table_size) { indexType hashIndex; @@ -670,12 +563,6 @@ int hashBv::getHashForIndex(indexType index, int table_size) return (int)hashIndex; } -int hashBv::getRehashForIndex(indexType thisIndex, int thisTableSize, int newTableSize) -{ - assert(0); - return 0; -} - hashBvNode** hashBv::getInsertionPointForIndex(indexType index) { indexType indexInNode; @@ -743,25 +630,6 @@ hashBvNode* hashBv::getNodeForIndexHelper(indexType index, bool canAdd) } } -hashBvNode* hashBv::getNodeForIndex(indexType index) -{ - // determine the base index of the node containing this index - index = index & ~(BITS_PER_NODE - 1); - - hashBvNode** prev = getInsertionPointForIndex(index); - - hashBvNode* node = *prev; - - if (node && node->belongsIn(index)) - { - return node; - } - else - { - return nullptr; - } -} - void hashBv::setBit(indexType index) { assert(index >= 0); @@ -1156,49 +1024,6 @@ class OrAction } }; -class CompareAction -{ -public: - static inline void PreAction(hashBv* lhs, hashBv* rhs) - { - } - static inline void PostAction(hashBv* lhs, hashBv* rhs) - { - } - static inline bool DefaultResult() - { - return true; - } - - static inline void LeftGap(hashBv* lhs, hashBvNode**& l, hashBvNode*& r, bool& result, bool& terminate) - { - terminate = true; - result = false; - } - static inline void RightGap(hashBv* lhs, hashBvNode**& l, hashBvNode*& r, bool& result, bool& terminate) - { - // in lhs, not rhs - // so skip lhs - terminate = true; - result = false; - } - static inline void BothPresent(hashBv* lhs, hashBvNode**& l, hashBvNode*& r, bool& result, bool& terminate) - { - if (!(*l)->sameAs(r)) - { - terminate = true; - result = false; - } - l = &((*l)->next); - r = r->next; - } - static inline void LeftEmpty(hashBv* lhs, hashBvNode**& l, hashBvNode*& r, bool& result, bool& terminate) - { - terminate = true; - result = false; - } -}; - class IntersectsAction { public: @@ -1526,18 +1351,6 @@ void hashBv::Subtract(hashBv* other) this->SubtractWithChange(other); } -void hashBv::Subtract3(hashBv* o1, hashBv* o2) -{ - this->copyFrom(o1, m_compiler); - this->Subtract(o2); -} - -void hashBv::UnionMinus(hashBv* src1, hashBv* src2, hashBv* src3) -{ - this->Subtract3(src1, src2); - this->OrWithChange(src3); -} - void hashBv::ZeroAll() { int hts = this->hashtable_size(); @@ -1573,11 +1386,6 @@ void hashBv::AndWith(hashBv* other) this->AndWithChange(other); } -bool hashBv::CompareWith(hashBv* other) -{ - return MultiTraverse(other); -} - void hashBv::copyFrom(hashBv* other, Compiler* comp) { assert(this != other); @@ -1643,154 +1451,6 @@ void hashBv::copyFrom(hashBv* other, Compiler* comp) #endif } -int nodeSort(const void* x, const void* y) -{ - hashBvNode* a = (hashBvNode*)x; - hashBvNode* b = (hashBvNode*)y; - return (int)(b->baseIndex - a->baseIndex); -} - -void hashBv::InorderTraverse(nodeAction n) -{ - int hts = hashtable_size(); - - hashBvNode** x = new (m_compiler, CMK_hashBv) hashBvNode*[hts]; - - { - // keep an array of the current pointers - // into each of the bitvector lists - // in the hashtable - for (int i = 0; i < hts; i++) - { - x[i] = nodeArr[i]; - } - - while (1) - { - // pick the lowest node in the hashtable - - indexType lowest = INT_MAX; - int lowest_index = -1; - for (int i = 0; i < hts; i++) - { - if (x[i] && x[i]->baseIndex < lowest) - { - lowest = x[i]->baseIndex; - lowest_index = i; - } - } - // if there was anything left, use it and update - // the list pointers otherwise we are done - if (lowest_index != -1) - { - n(x[lowest_index]); - x[lowest_index] = x[lowest_index]->next; - } - else - { - break; - } - } - } - - delete[] x; -} - -void hashBv::InorderTraverseTwo(hashBv* other, dualNodeAction a) -{ - int sizeThis, sizeOther; - hashBvNode **nodesThis, **nodesOther; - - sizeThis = this->hashtable_size(); - sizeOther = other->hashtable_size(); - - nodesThis = new (m_compiler, CMK_hashBv) hashBvNode*[sizeThis]; - nodesOther = new (m_compiler, CMK_hashBv) hashBvNode*[sizeOther]; - - // populate the arrays - for (int i = 0; i < sizeThis; i++) - { - nodesThis[i] = this->nodeArr[i]; - } - - for (int i = 0; i < sizeOther; i++) - { - nodesOther[i] = other->nodeArr[i]; - } - - while (1) - { - indexType lowestThis = INT_MAX; - indexType lowestOther = INT_MAX; - int lowestHashIndexThis = -1; - int lowestHashIndexOther = -1; - - // find the lowest remaining node in each BV - for (int i = 0; i < sizeThis; i++) - { - if (nodesThis[i] && nodesThis[i]->baseIndex < lowestThis) - { - lowestHashIndexThis = i; - lowestThis = nodesThis[i]->baseIndex; - } - } - for (int i = 0; i < sizeOther; i++) - { - if (nodesOther[i] && nodesOther[i]->baseIndex < lowestOther) - { - lowestHashIndexOther = i; - lowestOther = nodesOther[i]->baseIndex; - } - } - hashBvNode *nodeThis, *nodeOther; - nodeThis = lowestHashIndexThis == -1 ? nullptr : nodesThis[lowestHashIndexThis]; - nodeOther = lowestHashIndexOther == -1 ? nullptr : nodesOther[lowestHashIndexOther]; - // no nodes left in either, so return - if ((!nodeThis) && (!nodeOther)) - { - break; - - // there are only nodes left in one bitvector - } - else if ((!nodeThis) || (!nodeOther)) - { - a(this, other, nodeThis, nodeOther); - if (nodeThis) - { - nodesThis[lowestHashIndexThis] = nodesThis[lowestHashIndexThis]->next; - } - if (nodeOther) - { - nodesOther[lowestHashIndexOther] = nodesOther[lowestHashIndexOther]->next; - } - } - // nodes are left in both so determine if the lowest ones - // match. if so process them in a pair. if not then - // process the lower of the two alone - else - { - if (nodeThis->baseIndex == nodeOther->baseIndex) - { - a(this, other, nodeThis, nodeOther); - nodesThis[lowestHashIndexThis] = nodesThis[lowestHashIndexThis]->next; - nodesOther[lowestHashIndexOther] = nodesOther[lowestHashIndexOther]->next; - } - else if (nodeThis->baseIndex < nodeOther->baseIndex) - { - a(this, other, nodeThis, nullptr); - nodesThis[lowestHashIndexThis] = nodesThis[lowestHashIndexThis]->next; - } - else if (nodeOther->baseIndex < nodeThis->baseIndex) - { - a(this, other, nullptr, nodeOther); - nodesOther[lowestHashIndexOther] = nodesOther[lowestHashIndexOther]->next; - } - } - } - delete[] nodesThis; - delete[] nodesOther; -} - // -------------------------------------------------------------------- // -------------------------------------------------------------------- @@ -1852,26 +1512,6 @@ hashBvIterator::hashBvIterator(hashBv* bv) } } -void hashBvIterator::initFrom(hashBv* bv) -{ - this->bv = bv; - this->hashtable_size = bv->hashtable_size(); - this->hashtable_index = 0; - this->currNode = bv->nodeArr[0]; - this->current_element = 0; - this->current_base = 0; - this->current_data = 0; - - if (!this->currNode) - { - this->nextNode(); - } - if (this->currNode) - { - this->current_data = this->currNode->elements[0]; - } -} - void hashBvIterator::nextNode() { // if we have a valid node then just get the next one in the chain diff --git a/src/coreclr/jit/hashbv.h b/src/coreclr/jit/hashbv.h index 2098814b6730b2..4bb71769ea022b 100644 --- a/src/coreclr/jit/hashbv.h +++ b/src/coreclr/jit/hashbv.h @@ -37,8 +37,6 @@ class hashBvIterator; class hashBvGlobalData; typedef void bitAction(indexType); -typedef void nodeAction(hashBvNode*); -typedef void dualNodeAction(hashBv* left, hashBv* right, hashBvNode* a, hashBvNode* b); #define NOMOREBITS -1 @@ -113,10 +111,8 @@ class hashBvNode bool anySet(); bool belongsIn(indexType index); int countBits(); - bool anyBits(); void foreachBit(bitAction x); void freeNode(hashBvGlobalData* glob); - bool sameAs(hashBvNode* other); void copyFrom(hashBvNode* other); void AndWith(hashBvNode* other); @@ -145,12 +141,7 @@ class hashBv hashBvNode** nodeArr; hashBvNode* initialVector[1]; - union - { - Compiler* m_compiler; - // for freelist - hashBv* next; - }; + Compiler* m_compiler; unsigned short log2_hashSize; // used for heuristic resizing... could be overflowed in rare circumstances @@ -161,8 +152,6 @@ class hashBv hashBv(Compiler* comp); static hashBv* Create(Compiler* comp); static void Init(Compiler* comp); - static hashBv* CreateFrom(hashBv* other, Compiler* comp); - void hbvFree(); #ifdef DEBUG void dump(); void dumpFancy(); @@ -174,15 +163,11 @@ class hashBv hashBvGlobalData* globalData(); - static hashBvNode*& nodeFreeList(hashBvGlobalData* globalData); - static hashBv*& hbvFreeList(hashBvGlobalData* data); - hashBvNode** getInsertionPointForIndex(indexType index); private: hashBvNode* getNodeForIndexHelper(indexType index, bool canAdd); int getHashForIndex(indexType index, int table_size); - int getRehashForIndex(indexType thisIndex, int thisTableSize, int newTableSize); // maintain free lists for vectors hashBvNode** getNewVector(int vectorLength); @@ -194,8 +179,6 @@ class hashBv hashBvNode* temp = getNodeForIndexHelper(index, true); return temp; } - hashBvNode* getNodeForIndex(indexType index); - void removeNodeAtBase(indexType index); public: void setBit(indexType index); @@ -206,20 +189,14 @@ class hashBv bool anySet(); void copyFrom(hashBv* other, Compiler* comp); void ZeroAll(); - bool CompareWith(hashBv* other); void AndWith(hashBv* other); void OrWith(hashBv* other); void XorWith(hashBv* other); void Subtract(hashBv* other); - void Subtract3(hashBv* other, hashBv* other2); - - void UnionMinus(hashBv* a, hashBv* b, hashBv* c); bool AndWithChange(hashBv* other); bool OrWithChange(hashBv* other); - bool OrWithChangeRight(hashBv* other); - bool OrWithChangeLeft(hashBv* other); bool XorWithChange(hashBv* other); bool SubtractWithChange(hashBv* other); @@ -234,15 +211,8 @@ class hashBv template bool MultiTraverse(hashBv* other); - void InorderTraverse(nodeAction a); - void InorderTraverseTwo(hashBv* other, dualNodeAction a); - void Resize(int newSize); void Resize(); - void MergeLists(hashBvNode** a, hashBvNode** b); - - bool TooSmall(); - bool TooBig(); bool IsValid(); }; @@ -263,7 +233,6 @@ class hashBvIterator elemType current_data; hashBvIterator(hashBv* bv); - void initFrom(hashBv* bv); hashBvIterator(); indexType nextBit(); @@ -277,7 +246,6 @@ class hashBvGlobalData friend class hashBvNode; hashBvNode* hbvNodeFreeList; - hashBv* hbvFreeList; }; enum class HbvWalk diff --git a/src/coreclr/jit/jiteh.cpp b/src/coreclr/jit/jiteh.cpp index f1d29578c94e08..179d0181b9118b 100644 --- a/src/coreclr/jit/jiteh.cpp +++ b/src/coreclr/jit/jiteh.cpp @@ -929,35 +929,12 @@ void Compiler::ehUpdateForDeletedBlock(BasicBlock* block) /***************************************************************************** * Determine if an empty block can be deleted, and still preserve the EH normalization * rules on blocks. - * - * We only consider the case where the block to be deleted is the last block of a region, - * and the region is being contracted such that the previous block will become the new - * 'last' block. If this previous block is already a 'last' block, then we can't do the - * delete, as that would cause a single block to be the 'last' block of multiple regions. */ bool Compiler::ehCanDeleteEmptyBlock(BasicBlock* block) { assert(block->isEmpty()); return true; - -#if 0 // This is disabled while the "multiple last block" normalization is disabled - if (!fgNormalizeEHDone) - { - return true; - } - - if (ehIsBlockEHLast(block)) - { - BasicBlock* bPrev = block->Prev(); - if ((bPrev != nullptr) && ehIsBlockEHLast(bPrev)) - { - return false; - } - } - - return true; -#endif // 0 } /***************************************************************************** @@ -2126,39 +2103,8 @@ void Compiler::fgSortEHTable() // entries must keep the same "try" region begin/last block pointers. A block in this "try" region has a try index // of the first ("most nested") EH table entry. // -// 3. No block is the last block of more than one try or handler region. Again, as described above, -// filters need not be considered. -// -// For example, we will transform this: -// -// try3 ----------------- BB01 -// | try2 ---------- BB02 -// | | handler1 BB03 -// | | | BB04 -// |----- |----- |------- BB05 -// -// (where all three try regions end at BB05) to this: -// -// try3 ----------------- BB01 -// | try2 ---------- BB02 -// | | handler1 BB03 -// | | | BB04 -// | | |------- BB05 -// | |-------------- BB06 // empty BBJ_ALWAYS block -// |--------------------- BB07 // empty BBJ_ALWAYS block -// -// No branches need to change: if something branched to BB05, it will still branch to BB05. If BB05 is a -// BBJ_ALWAYS block to the next block, then control flow will fall through the newly added blocks as well. -// If it is anything else, it will retain that block branch type and BB06 and BB07 will be unreachable. -// -// The benefit of this is, once again, to remove the need to consider every EH region when adding new blocks. -// -// Overall, a block can appear in the EH table exactly once: as the begin or last block of a single try, filter, or -// handler. There is one exception: for a single-block EH region, the block can appear as both the "begin" and "last" -// block of the try, or the "begin" and "last" block of the handler (note that filters don't have a "last" block stored, -// so this case doesn't apply.) -// (Note: we could remove this special case if we wanted, and if it helps anything, but it doesn't appear that it will -// help.) +// A block begins at most one EH region, except for mutually protecting try regions. +// Multiple EH regions may still share their last block. // // These invariants simplify a number of things. When inserting a new block into a region, it is not necessary to // traverse the entire EH table looking to see if any EH region needs to be updated. You only ever need to update a @@ -2195,27 +2141,13 @@ void Compiler::fgNormalizeEH() modified = true; } - // Case #2: Prevent any two EH regions from starting with the same block (after case #3, we only need to worry about + // Case #2: Prevent any two EH regions from starting with the same block (after case #1, we only need to worry about // 'try' blocks). if (fgNormalizeEHCase2()) { modified = true; } -#if 0 - // Case 3 normalization is disabled. The JIT really doesn't like having extra empty blocks around, especially - // blocks that are unreachable. There are lots of asserts when such things occur. We will re-evaluate whether we - // can do this normalization. - // Note: there are cases in fgVerifyHandlerTab() that are also disabled to match this. - - // Case #3: Prevent any two EH regions from ending with the same block. - if (fgNormalizeEHCase3()) - { - modified = true; - } - -#endif // 0 - INDEBUG(fgNormalizeEHDone = true;) if (modified) @@ -2681,421 +2613,6 @@ bool Compiler::fgCreateFiltersForGenericExceptions() return madeChanges; } -bool Compiler::fgNormalizeEHCase3() -{ - bool modified = false; - - // - // Case #3: Make sure no two 'try' or handler regions have the same 'last' block (except for mutually protect 'try' - // regions). As above, there has to be EH region nesting for this to occur. However, since we need to consider - // handlers, there are more cases. - // - // There are four cases to consider: - // (1) try nested in try - // (2) handler nested in try - // (3) try nested in handler - // (4) handler nested in handler - // - // Note that, before funclet generation, it would be unusual, though legal IL, for a 'try' to come at the end - // of an EH region (either 'try' or handler region), since that implies that its corresponding handler precedes it. - // That will never happen in C#, but is legal in IL. - // - // Only one of these cases can happen. For example, if we have case (2), where a try/catch is nested in a 'try' and - // the nested handler has the same 'last' block as the outer handler, then, due to nesting rules, the nested 'try' - // must also be within the outer handler, and obviously cannot share the same 'last' block. - // - - for (unsigned XTnum = 0; XTnum < compHndBBtabCount; XTnum++) - { - EHblkDsc* eh = ehGetDsc(XTnum); - - // Find the EH region 'eh' is most nested within, either 'try' or handler or none. - bool outerIsTryRegion; - unsigned ehOuterIndex = eh->ebdGetEnclosingRegionIndex(&outerIsTryRegion); - - if (ehOuterIndex != EHblkDsc::NO_ENCLOSING_INDEX) - { - EHblkDsc* ehInner = eh; // This gets updated as we loop outwards in the EH nesting - unsigned ehInnerIndex = XTnum; // This gets updated as we loop outwards in the EH nesting - bool innerIsTryRegion; - - EHblkDsc* ehOuter = ehGetDsc(ehOuterIndex); - - // Debugging: say what type of block we're updating. - INDEBUG(const char* outerType = ""; const char* innerType = "";) - - // 'insertAfterBlk' is the place we will insert new "normalization" blocks. We don't know yet if we will - // insert them after the innermost 'try' or handler's "last" block, so we set it to nullptr. Once we - // determine the innermost region that is equivalent, we set this, and then update it incrementally as we - // loop outwards. - BasicBlock* insertAfterBlk = nullptr; - - bool foundMatchingLastBlock = false; - - // This is set to 'false' for mutual protect regions for which we will not insert a normalization block. - bool insertNormalizationBlock = true; - - // Keep track of what the 'try' index and handler index should be for any new normalization block that we - // insert. If we have a sequence of alternating nested 'try' and handlers with the same 'last' block, we'll - // need to update these as we go. For example: - // try { // EH#5 - // ... - // catch { // EH#4 - // ... - // try { // EH#3 - // ... - // catch { // EH#2 - // ... - // try { // EH#1 - // BB01 // try=1, hnd=2 - // } } } } } // all the 'last' blocks are the same - // - // after normalization: - // - // try { // EH#5 - // ... - // catch { // EH#4 - // ... - // try { // EH#3 - // ... - // catch { // EH#2 - // ... - // try { // EH#1 - // BB01 // try=1, hnd=2 - // } - // BB02 // try=3, hnd=2 - // } - // BB03 // try=3, hnd=4 - // } - // BB04 // try=5, hnd=4 - // } - // BB05 // try=5, hnd=0 (no enclosing hnd) - // } - // - unsigned nextTryIndex = EHblkDsc::NO_ENCLOSING_INDEX; // Initialization only needed to quell compiler - // warnings. - unsigned nextHndIndex = EHblkDsc::NO_ENCLOSING_INDEX; - - // We compare the outer region against the inner region's 'try' or handler, determined by the - // 'outerIsTryRegion' variable. Once we decide that, we know exactly the 'last' pointer that we will use to - // compare against all enclosing EH regions. - // - // For example, if we have these nested EH regions (omitting some corresponding try/catch clauses for each - // nesting level): - // - // try { - // ... - // catch { - // ... - // try { - // } } } // all the 'last' blocks are the same - // - // then we determine that the innermost region we are going to compare against is the 'try' region. There's - // no reason to compare against its handler region for any enclosing region (since it couldn't possibly - // share a 'last' block with the enclosing region). However, there's no harm, either (and it simplifies - // the code for the first set of comparisons to be the same as subsequent, more enclosing cases). - BasicBlock* lastBlockPtrToCompare = nullptr; - - // We need to keep track of the last "mutual protect" region so we can properly not add additional blocks - // to the second and subsequent mutual protect try blocks. We can't just keep track of the EH region - // pointer, because we're updating the last blocks as we go. So, we need to keep track of the - // pre-update 'try' begin/last blocks themselves. These only matter if the "last" blocks that match are - // from two (or more) nested 'try' regions. - BasicBlock* mutualTryBeg = nullptr; - BasicBlock* mutualTryLast = nullptr; - - if (outerIsTryRegion) - { - nextTryIndex = EHblkDsc::NO_ENCLOSING_INDEX; // unused, since the outer block is a 'try' region. - - // The outer (enclosing) region is a 'try' - if (ehOuter->ebdTryLast == ehInner->ebdTryLast) - { - // Case (1) try nested in try. - foundMatchingLastBlock = true; - INDEBUG(innerType = "try"; outerType = "try";) - insertAfterBlk = ehOuter->ebdTryLast; - lastBlockPtrToCompare = insertAfterBlk; - - if (EHblkDsc::ebdIsSameTry(ehOuter, ehInner)) - { - // We can't touch this 'try', since it's mutual protect. -#ifdef DEBUG - if (verbose) - { - printf("Mutual protect regions EH#%u and EH#%u; leaving identical 'try' last blocks.\n", - ehOuterIndex, ehInnerIndex); - } -#endif // DEBUG - - insertNormalizationBlock = false; - } - else - { - nextHndIndex = ehInner->ebdTryLast->hasHndIndex() ? ehInner->ebdTryLast->getHndIndex() - : EHblkDsc::NO_ENCLOSING_INDEX; - } - } - else if (ehOuter->ebdTryLast == ehInner->ebdHndLast) - { - // Case (2) handler nested in try. - foundMatchingLastBlock = true; - INDEBUG(innerType = "handler"; outerType = "try";) - insertAfterBlk = ehOuter->ebdTryLast; - lastBlockPtrToCompare = insertAfterBlk; - - assert(ehInner->ebdHndLast->getHndIndex() == ehInnerIndex); - nextHndIndex = ehInner->ebdEnclosingHndIndex; - } - else - { - // No "last" pointers match! - } - - if (foundMatchingLastBlock) - { - // The outer might be part of a new set of mutual protect regions (if it isn't part of one already). - mutualTryBeg = ehOuter->ebdTryBeg; - mutualTryLast = ehOuter->ebdTryLast; - } - } - else - { - nextHndIndex = EHblkDsc::NO_ENCLOSING_INDEX; // unused, since the outer block is a handler region. - - // The outer (enclosing) region is a handler (note that it can't be a filter; there is no nesting - // within a filter). - if (ehOuter->ebdHndLast == ehInner->ebdTryLast) - { - // Case (3) try nested in handler. - foundMatchingLastBlock = true; - INDEBUG(innerType = "try"; outerType = "handler";) - insertAfterBlk = ehOuter->ebdHndLast; - lastBlockPtrToCompare = insertAfterBlk; - - assert(ehInner->ebdTryLast->getTryIndex() == ehInnerIndex); - nextTryIndex = ehInner->ebdEnclosingTryIndex; - } - else if (ehOuter->ebdHndLast == ehInner->ebdHndLast) - { - // Case (4) handler nested in handler. - foundMatchingLastBlock = true; - INDEBUG(innerType = "handler"; outerType = "handler";) - insertAfterBlk = ehOuter->ebdHndLast; - lastBlockPtrToCompare = insertAfterBlk; - - nextTryIndex = ehInner->ebdTryLast->hasTryIndex() ? ehInner->ebdTryLast->getTryIndex() - : EHblkDsc::NO_ENCLOSING_INDEX; - } - else - { - // No "last" pointers match! - } - } - - while (foundMatchingLastBlock) - { - assert(lastBlockPtrToCompare != nullptr); - assert(insertAfterBlk != nullptr); - assert(ehOuterIndex != EHblkDsc::NO_ENCLOSING_INDEX); - assert(ehOuter != nullptr); - - // Add a normalization block - - if (insertNormalizationBlock) - { - // Add a new last block for 'ehOuter' that will be outside the EH region with which it encloses and - // shares a 'last' pointer - - BasicBlock* newLast = BasicBlock::New(this); - newLast->bbRefs = 0; - assert(insertAfterBlk != nullptr); - fgInsertBBafter(insertAfterBlk, newLast); - -#ifdef DEBUG - if (verbose) - { - printf( - "last %s block for EH#%u and last %s block for EH#%u are same block; inserted new " FMT_BB - " after " FMT_BB " as new last %s block for EH#%u.\n", - outerType, ehOuterIndex, innerType, ehInnerIndex, newLast->bbNum, insertAfterBlk->bbNum, - outerType, ehOuterIndex); - } -#endif // DEBUG - - if (outerIsTryRegion) - { - ehOuter->ebdTryLast = newLast; - newLast->setTryIndex(ehOuterIndex); - if (nextHndIndex == EHblkDsc::NO_ENCLOSING_INDEX) - { - newLast->clearHndIndex(); - } - else - { - newLast->setHndIndex(nextHndIndex); - } - } - else - { - ehOuter->ebdHndLast = newLast; - if (nextTryIndex == EHblkDsc::NO_ENCLOSING_INDEX) - { - newLast->clearTryIndex(); - } - else - { - newLast->setTryIndex(nextTryIndex); - } - newLast->setHndIndex(ehOuterIndex); - } - - newLast->SetCatchType(BBCT_NONE); // bbCatchType is only set on the first block of a handler, which - // is this not - newLast->bbCodeOffs = insertAfterBlk->bbCodeOffsEnd; - newLast->bbCodeOffsEnd = newLast->bbCodeOffs; // code size = 0. TODO: use BAD_IL_OFFSET instead? - newLast->inheritWeight(insertAfterBlk); - newLast->SetFlags(BBF_INTERNAL); - FlowEdge* const newEdge = fgAddRefPred(newLast, insertAfterBlk); - insertAfterBlk->SetKindAndTargetEdge(BBJ_ALWAYS, newEdge); - - // Move the insert pointer. More enclosing equivalent 'last' blocks will be inserted after this. - insertAfterBlk = newLast; - - modified = true; - -#ifdef DEBUG - if (verbose) // Normally this is way too verbose, but it is useful for debugging - { - printf("*************** fgNormalizeEH() made a change\n"); - fgDispBasicBlocks(); - fgDispHandlerTab(); - } -#endif // DEBUG - } - - // Now find the next outer enclosing EH region and see if it also shares the last block. - foundMatchingLastBlock = false; // assume nothing will match - ehInner = ehOuter; - ehInnerIndex = ehOuterIndex; - innerIsTryRegion = outerIsTryRegion; - - ehOuterIndex = - ehOuter->ebdGetEnclosingRegionIndex(&outerIsTryRegion); // Loop outwards in the EH nesting. - if (ehOuterIndex != EHblkDsc::NO_ENCLOSING_INDEX) - { - // There are more enclosing regions; check for equivalent 'last' pointers. - - INDEBUG(innerType = outerType; outerType = "";) - - ehOuter = ehGetDsc(ehOuterIndex); - - insertNormalizationBlock = true; // assume it's not mutual protect - - if (outerIsTryRegion) - { - nextTryIndex = EHblkDsc::NO_ENCLOSING_INDEX; // unused, since the outer block is a 'try' region. - - // The outer (enclosing) region is a 'try' - if (ehOuter->ebdTryLast == lastBlockPtrToCompare) - { - // Case (1) and (2): try or handler nested in try. - foundMatchingLastBlock = true; - INDEBUG(outerType = "try";) - - if (innerIsTryRegion && ehOuter->ebdIsSameTry(mutualTryBeg, mutualTryLast)) - { - // We can't touch this 'try', since it's mutual protect. - -#ifdef DEBUG - if (verbose) - { - printf("Mutual protect regions EH#%u and EH#%u; leaving identical 'try' last " - "blocks.\n", - ehOuterIndex, ehInnerIndex); - } -#endif // DEBUG - - insertNormalizationBlock = false; - - // We still need to update the 'last' pointer, in case someone inserted a normalization - // block before the start of the mutual protect 'try' region. - ehOuter->ebdTryLast = insertAfterBlk; - } - else - { - if (innerIsTryRegion) - { - // Case (1) try nested in try. - nextHndIndex = ehInner->ebdTryLast->hasHndIndex() - ? ehInner->ebdTryLast->getHndIndex() - : EHblkDsc::NO_ENCLOSING_INDEX; - } - else - { - // Case (2) handler nested in try. - assert(ehInner->ebdHndLast->getHndIndex() == ehInnerIndex); - nextHndIndex = ehInner->ebdEnclosingHndIndex; - } - } - - // The outer might be part of a new set of mutual protect regions (if it isn't part of one - // already). - mutualTryBeg = ehOuter->ebdTryBeg; - mutualTryLast = ehOuter->ebdTryLast; - } - } - else - { - nextHndIndex = - EHblkDsc::NO_ENCLOSING_INDEX; // unused, since the outer block is a handler region. - - // The outer (enclosing) region is a handler (note that it can't be a filter; there is no - // nesting within a filter). - if (ehOuter->ebdHndLast == lastBlockPtrToCompare) - { - // Case (3) and (4): try nested in try or handler. - foundMatchingLastBlock = true; - INDEBUG(outerType = "handler";) - - if (innerIsTryRegion) - { - // Case (3) try nested in handler. - assert(ehInner->ebdTryLast->getTryIndex() == ehInnerIndex); - nextTryIndex = ehInner->ebdEnclosingTryIndex; - } - else - { - // Case (4) handler nested in handler. - nextTryIndex = ehInner->ebdTryLast->hasTryIndex() ? ehInner->ebdTryLast->getTryIndex() - : EHblkDsc::NO_ENCLOSING_INDEX; - } - } - } - } - - // If we get to here and foundMatchingLastBlock is false, then the inner and outer region don't share - // any 'last' blocks, so we're done. Note that we could have a situation like this: - // - // try4 try3 try2 try1 - // |---- | | | BB01 - // | |---- | | BB02 - // | | |---- | BB03 - // | | | |----- BB04 - // | | |----- |----- BB05 - // |---- |------------------- BB06 - // - // (Thus, try1 & try2 end at BB05, and are nested inside try3 & try4, which both end at BB06.) - // In this case, we'll process try1 and try2, then break out. Later, as we iterate through the EH table, - // we'll get to try3 and process it and try4. - - } // end while (foundMatchingLastBlock) - } // if (ehOuterIndex != EHblkDsc::NO_ENCLOSING_INDEX) - } // EH table iteration - - return modified; -} - /*****************************************************************************/ #ifdef DEBUG @@ -3221,10 +2738,6 @@ void Compiler::fgVerifyHandlerTab() // block (case 2)? bool multipleBegBlockNormalizationDone = fgNormalizeEHDone; - // Did we do the normalization that prevents multiple EH regions ('try' or handler blocks) from ending on the same - // block (case 3)? - bool multipleLastBlockNormalizationDone = false; // Currently disabled - BitVecTraits traits(impInlineRoot()->compEHID, this); BitVec ids(BitVecOps::MakeEmpty(&traits)); @@ -3478,16 +2991,7 @@ void Compiler::fgVerifyHandlerTab() assert(bbNumOuterTryBeg <= bbNumTryBeg); } - if (multipleLastBlockNormalizationDone) - { - // Two 'try' regions can't end at the same block - // (by EH normalization). - assert(bbNumTryLast < bbNumOuterTryLast); - } - else - { - assert(bbNumTryLast <= bbNumOuterTryLast); - } + assert(bbNumTryLast <= bbNumOuterTryLast); } } else @@ -3518,17 +3022,8 @@ void Compiler::fgVerifyHandlerTab() // An inner handler can never start at the same // block as an outer 'try' (by IL rules). assert(bbNumOuterTryBeg < bbNumHndBeg); - if (multipleLastBlockNormalizationDone) - { - // An inner EH region can't share a 'last' block with the outer 'try' (by EH normalization). - assert(bbNumTryLast < bbNumOuterTryLast); - assert(bbNumHndLast < bbNumOuterTryLast); - } - else - { - assert(bbNumTryLast <= bbNumOuterTryLast); - assert(bbNumHndLast <= bbNumOuterTryLast); - } + assert(bbNumTryLast <= bbNumOuterTryLast); + assert(bbNumHndLast <= bbNumOuterTryLast); } } } @@ -3564,15 +3059,7 @@ void Compiler::fgVerifyHandlerTab() { assert(bbNumOuterHndBeg <= bbNumTryBeg); } - if (multipleLastBlockNormalizationDone) - { - assert(bbNumTryLast < bbNumOuterHndLast); // An inner 'try' can't end at the same block as an - // outer handler (by EH normalization). - } - else - { - assert(bbNumTryLast <= bbNumOuterHndLast); - } + assert(bbNumTryLast <= bbNumOuterHndLast); // With funclets, all we can say about the handler blocks is that they are disjoint from the enclosing // handler. @@ -3591,17 +3078,8 @@ void Compiler::fgVerifyHandlerTab() } assert(bbNumOuterHndBeg < bbNumHndBeg); // An inner handler can never start at the same block // as an outer handler (by IL rules). - if (multipleLastBlockNormalizationDone) - { - // An inner EH region can't share a 'last' block with the outer handler (by EH normalization). - assert(bbNumTryLast < bbNumOuterHndLast); - assert(bbNumHndLast < bbNumOuterHndLast); - } - else - { - assert(bbNumTryLast <= bbNumOuterHndLast); - assert(bbNumHndLast <= bbNumOuterHndLast); - } + assert(bbNumTryLast <= bbNumOuterHndLast); + assert(bbNumHndLast <= bbNumOuterHndLast); } } diff --git a/src/coreclr/jit/layout.cpp b/src/coreclr/jit/layout.cpp index bab2187244d819..b550bf496dc4cb 100644 --- a/src/coreclr/jit/layout.cpp +++ b/src/coreclr/jit/layout.cpp @@ -64,19 +64,10 @@ struct CustomLayoutKey } }; -// Keeps track of layout objects associated to class handles or block sizes. A layout is usually -// referenced by a pointer (ClassLayout*) but can also be referenced by a number (unsigned, -// FirstLayoutNum-based), when space constraints or other needs make numbers more appealing. -// Layout objects are immutable and there's always a 1:1 mapping between class handles/block sizes, -// pointers and numbers (e.g. class handle equality implies ClassLayout pointer equality). +// Keeps track of immutable layout objects associated with class handles or custom layouts. +// Equivalent class handles or custom layouts map to the same ClassLayout pointer. class ClassLayoutTable { - // Each layout is assigned a number, starting with TYP_UNKNOWN + 1. This way one could use a single - // unsigned value to represent the notion of type - values below TYP_UNKNOWN are var_types and values - // above it are struct layouts. - static constexpr unsigned ZeroSizedBlockLayoutNum = TYP_UNKNOWN + 1; - static constexpr unsigned FirstLayoutNum = TYP_UNKNOWN + 2; - typedef JitHashTable CustomLayoutIndexMap; typedef JitHashTable, unsigned> ObjLayoutIndexMap; @@ -108,30 +99,6 @@ class ClassLayoutTable { } - // Get a number that uniquely identifies the specified layout. - unsigned GetLayoutNum(ClassLayout* layout) const - { - if (layout == &m_zeroSizedBlockLayout) - { - return ZeroSizedBlockLayoutNum; - } - - return GetLayoutIndex(layout) + FirstLayoutNum; - } - - // Get the layout that corresponds to the specified identifier number. - ClassLayout* GetLayoutByNum(unsigned num) const - { - if (num == ZeroSizedBlockLayoutNum) - { - // Fine to cast away const as ClassLayout is immutable - return const_cast(&m_zeroSizedBlockLayout); - } - - assert(num >= FirstLayoutNum); - return GetLayoutByIndex(num - FirstLayoutNum); - } - // Get the layout having the specified size but no class handle. ClassLayout* GetCustomLayout(Compiler* compiler, const ClassLayoutBuilder& builder) { @@ -143,29 +110,12 @@ class ClassLayoutTable return GetLayoutByIndex(GetCustomLayoutIndex(compiler, builder)); } - // Get a number that uniquely identifies a layout having the specified size but no class handle. - unsigned GetCustomLayoutNum(Compiler* compiler, const ClassLayoutBuilder& builder) - { - if (builder.m_size == 0) - { - return ZeroSizedBlockLayoutNum; - } - - return GetCustomLayoutIndex(compiler, builder) + FirstLayoutNum; - } - // Get the layout for the specified class handle. ClassLayout* GetObjLayout(Compiler* compiler, CORINFO_CLASS_HANDLE classHandle) { return GetLayoutByIndex(GetObjLayoutIndex(compiler, classHandle)); } - // Get a number that uniquely identifies a layout for the specified class handle. - unsigned GetObjLayoutNum(Compiler* compiler, CORINFO_CLASS_HANDLE classHandle) - { - return GetObjLayoutIndex(compiler, classHandle) + FirstLayoutNum; - } - private: bool HasSmallCapacity() const { @@ -186,34 +136,6 @@ class ClassLayoutTable } } - unsigned GetLayoutIndex(ClassLayout* layout) const - { - assert(layout != nullptr); - assert(layout != &m_zeroSizedBlockLayout); - - if (HasSmallCapacity()) - { - for (unsigned i = 0; i < m_layoutCount; i++) - { - if (m_layoutArray[i] == layout) - { - return i; - } - } - } - else - { - unsigned index = 0; - if (layout->IsCustomLayout() ? m_customLayoutMap->Lookup(CustomLayoutKey(layout), &index) - : m_objLayoutMap->Lookup(layout->GetClassHandle(), &index)) - { - return index; - } - } - - unreached(); - } - unsigned GetCustomLayoutIndex(Compiler* compiler, const ClassLayoutBuilder& builder) { // The 0-sized layout has its own fast path. @@ -374,41 +296,16 @@ ClassLayoutTable* Compiler::typGetClassLayoutTable() return m_classLayoutTable; } -ClassLayout* Compiler::typGetLayoutByNum(unsigned layoutNum) -{ - return typGetClassLayoutTable()->GetLayoutByNum(layoutNum); -} - -unsigned Compiler::typGetLayoutNum(ClassLayout* layout) -{ - return typGetClassLayoutTable()->GetLayoutNum(layout); -} - -unsigned Compiler::typGetObjLayoutNum(CORINFO_CLASS_HANDLE classHandle) -{ - return typGetClassLayoutTable()->GetObjLayoutNum(this, classHandle); -} - ClassLayout* Compiler::typGetObjLayout(CORINFO_CLASS_HANDLE classHandle) { return typGetClassLayoutTable()->GetObjLayout(this, classHandle); } -unsigned Compiler::typGetCustomLayoutNum(const ClassLayoutBuilder& builder) -{ - return typGetClassLayoutTable()->GetCustomLayoutNum(this, builder); -} - ClassLayout* Compiler::typGetCustomLayout(const ClassLayoutBuilder& builder) { return typGetClassLayoutTable()->GetCustomLayout(this, builder); } -unsigned Compiler::typGetBlkLayoutNum(unsigned blockSize) -{ - return typGetCustomLayoutNum(ClassLayoutBuilder(this, blockSize)); -} - ClassLayout* Compiler::typGetBlkLayout(unsigned blockSize) { return typGetCustomLayout(ClassLayoutBuilder(this, blockSize)); diff --git a/src/coreclr/jit/utils.cpp b/src/coreclr/jit/utils.cpp index 17263b34b48ec5..7bba5a6f28b20a 100644 --- a/src/coreclr/jit/utils.cpp +++ b/src/coreclr/jit/utils.cpp @@ -2368,21 +2368,6 @@ double FloatingPointUtils::infinite_double() return *reinterpret_cast(&bits); } -//------------------------------------------------------------------------ -// infinite_float: return an infinite float value -// -// Returns: -// Infinite float value. -// -// Notes: -// This is the predefined constant HUGE_VALF on many platforms. -// -float FloatingPointUtils::infinite_float() -{ - int32_t bits = 0x7F800000; - return *reinterpret_cast(&bits); -} - //------------------------------------------------------------------------ // hasPreciseReciprocal: check double for precise reciprocal. E.g. 2.0 <--> 0.5 // @@ -2618,70 +2603,6 @@ double FloatingPointUtils::maximum(double val1, double val2) return isNegative(val2) ? val1 : val2; } -//------------------------------------------------------------------------ -// maximumMagnitude: This matches the IEEE 754:2019 `maximumMagnitude` function -// -// It propagates NaN inputs back to the caller and -// otherwise returns the input with a greater magnitude. -// It treats +0 as greater than -0 as per the specification. -// -// Arguments: -// x - left operand -// y - right operand -// -// Return Value: -// Either x or y -// -double FloatingPointUtils::maximumMagnitude(double x, double y) -{ - double ax = fabs(x); - double ay = fabs(y); - - if ((ax > ay) || isNaN(ax)) - { - return x; - } - - if (ax == ay) - { - return isNegative(x) ? y : x; - } - - return y; -} - -//------------------------------------------------------------------------ -// maximumMagnitudeNumber: // This matches the IEEE 754:2019 `maximumMagnitudeNumber` function -// -// It does not propagate NaN inputs back to the caller and -// otherwise returns the input with a larger magnitude. -// It treats +0 as larger than -0 as per the specification. -// -// Arguments: -// x - left operand -// y - right operand -// -// Return Value: -// Either x or y -// -double FloatingPointUtils::maximumMagnitudeNumber(double x, double y) -{ - double ax = fabs(x); - double ay = fabs(y); - - if ((ax > ay) || isNaN(ay)) - { - return x; - } - - if (ax == ay) - { - return isNegative(x) ? y : x; - } - - return y; -} - //------------------------------------------------------------------------ // maximumNumber: This matches the IEEE 754:2019 `maximumNumber` function // @@ -2740,70 +2661,6 @@ float FloatingPointUtils::maximum(float val1, float val2) return isNegative(val2) ? val1 : val2; } -//------------------------------------------------------------------------ -// maximumMagnitude: This matches the IEEE 754:2019 `maximumMagnitude` function -// -// It propagates NaN inputs back to the caller and -// otherwise returns the input with a greater magnitude. -// It treats +0 as greater than -0 as per the specification. -// -// Arguments: -// x - left operand -// y - right operand -// -// Return Value: -// Either x or y -// -float FloatingPointUtils::maximumMagnitude(float x, float y) -{ - float ax = fabsf(x); - float ay = fabsf(y); - - if ((ax > ay) || isNaN(ax)) - { - return x; - } - - if (ax == ay) - { - return isNegative(x) ? y : x; - } - - return y; -} - -//------------------------------------------------------------------------ -// maximumMagnitudeNumber: This matches the IEEE 754:2019 `maximumMagnitudeNumber` function -// -// It does not propagate NaN inputs back to the caller and -// otherwise returns the input with a larger magnitude. -// It treats +0 as larger than -0 as per the specification. -// -// Arguments: -// x - left operand -// y - right operand -// -// Return Value: -// Either x or y -// -float FloatingPointUtils::maximumMagnitudeNumber(float x, float y) -{ - float ax = fabsf(x); - float ay = fabsf(y); - - if ((ax > ay) || isNaN(ay)) - { - return x; - } - - if (ax == ay) - { - return isNegative(x) ? y : x; - } - - return y; -} - //------------------------------------------------------------------------ // maximumNumber: This matches the IEEE 754:2019 `maximumNumber` function // @@ -2862,70 +2719,6 @@ double FloatingPointUtils::minimum(double val1, double val2) return isNegative(val1) ? val1 : val2; } -//------------------------------------------------------------------------ -// minimumMagnitude: This matches the IEEE 754:2019 `minimumMagnitude` function -// -// It propagates NaN inputs back to the caller and -// otherwise returns the input with a lesser magnitude. -// It treats +0 as greater than -0 as per the specification. -// -// Arguments: -// x - left operand -// y - right operand -// -// Return Value: -// Either x or y -// -double FloatingPointUtils::minimumMagnitude(double x, double y) -{ - double ax = fabs(x); - double ay = fabs(y); - - if ((ax < ay) || isNaN(ax)) - { - return x; - } - - if (ax == ay) - { - return isNegative(x) ? x : y; - } - - return y; -} - -//------------------------------------------------------------------------ -// minimumMagnitudeNumber: This matches the IEEE 754:2019 `minimumMagnitudeNumber` function -// -// It does not propagate NaN inputs back to the caller and -// otherwise returns the input with a larger magnitude. -// It treats +0 as larger than -0 as per the specification. -// -// Arguments: -// x - left operand -// y - right operand -// -// Return Value: -// Either x or y -// -double FloatingPointUtils::minimumMagnitudeNumber(double x, double y) -{ - double ax = fabs(x); - double ay = fabs(y); - - if ((ax < ay) || isNaN(ay)) - { - return x; - } - - if (ax == ay) - { - return isNegative(x) ? x : y; - } - - return y; -} - //------------------------------------------------------------------------ // minimumNumber: This matches the IEEE 754:2019 `minimumNumber` function // @@ -2984,70 +2777,6 @@ float FloatingPointUtils::minimum(float val1, float val2) return isNegative(val1) ? val1 : val2; } -//------------------------------------------------------------------------ -// minimumMagnitude: This matches the IEEE 754:2019 `minimumMagnitude` function -// -// It propagates NaN inputs back to the caller and -// otherwise returns the input with a lesser magnitude. -// It treats +0 as greater than -0 as per the specification. -// -// Arguments: -// x - left operand -// y - right operand -// -// Return Value: -// Either x or y -// -float FloatingPointUtils::minimumMagnitude(float x, float y) -{ - float ax = fabsf(x); - float ay = fabsf(y); - - if ((ax < ay) || isNaN(ax)) - { - return x; - } - - if (ax == ay) - { - return isNegative(x) ? x : y; - } - - return y; -} - -//------------------------------------------------------------------------ -// minimumMagnitudeNumber: This matches the IEEE 754:2019 `minimumMagnitudeNumber` function -// -// It does not propagate NaN inputs back to the caller and -// otherwise returns the input with a larger magnitude. -// It treats +0 as larger than -0 as per the specification. -// -// Arguments: -// x - left operand -// y - right operand -// -// Return Value: -// Either x or y -// -float FloatingPointUtils::minimumMagnitudeNumber(float x, float y) -{ - float ax = fabsf(x); - float ay = fabsf(y); - - if ((ax < ay) || isNaN(ay)) - { - return x; - } - - if (ax == ay) - { - return isNegative(x) ? x : y; - } - - return y; -} - //------------------------------------------------------------------------ // minimumNumber: This matches the IEEE 754:2019 `minimumNumber` function // diff --git a/src/coreclr/jit/utils.h b/src/coreclr/jit/utils.h index 06b72fc33cd71e..f8124c894bd241 100644 --- a/src/coreclr/jit/utils.h +++ b/src/coreclr/jit/utils.h @@ -868,8 +868,6 @@ class FloatingPointUtils static double infinite_double(); - static float infinite_float(); - static bool isAllBitsSet(float val); static bool isAllBitsSet(double val); @@ -892,34 +890,18 @@ class FloatingPointUtils static double maximum(double val1, double val2); - static double maximumMagnitude(double val1, double val2); - - static double maximumMagnitudeNumber(double val1, double val2); - static double maximumNumber(double val1, double val2); static float maximum(float val1, float val2); - static float maximumMagnitude(float val1, float val2); - - static float maximumMagnitudeNumber(float val1, float val2); - static float maximumNumber(float val1, float val2); static double minimum(double val1, double val2); - static double minimumMagnitude(double val1, double val2); - - static double minimumMagnitudeNumber(double val1, double val2); - static double minimumNumber(double val1, double val2); static float minimum(float val1, float val2); - static float minimumMagnitude(float val1, float val2); - - static float minimumMagnitudeNumber(float val1, float val2); - static float minimumNumber(float val1, float val2); static double normalize(double x);