diff options
Diffstat (limited to 'src/jit/gentree.cpp')
-rw-r--r-- | src/jit/gentree.cpp | 451 |
1 files changed, 66 insertions, 385 deletions
diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp index c5733b81e4..a2156d035e 100644 --- a/src/jit/gentree.cpp +++ b/src/jit/gentree.cpp @@ -450,7 +450,7 @@ bool GenTree::IsNodeProperlySized() const #define BASH_HASH_SIZE 211 -inline hashme(genTreeOps op1, genTreeOps op2) +inline unsigned hashme(genTreeOps op1, genTreeOps op2) { return ((op1 * 104729) ^ (op2 * 56569)) % BASH_HASH_SIZE; } @@ -15026,390 +15026,6 @@ bool Compiler::gtComplexityExceeds(GenTreePtr* tree, unsigned limit) } } -/* -XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -XX XX -XX BasicBlock XX -XX XX -XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -*/ - -#if MEASURE_BLOCK_SIZE -/* static */ -size_t BasicBlock::s_Size; -/* static */ -size_t BasicBlock::s_Count; -#endif // MEASURE_BLOCK_SIZE - -#ifdef DEBUG -// The max # of tree nodes in any BB -/* static */ -unsigned BasicBlock::s_nMaxTrees; -#endif // DEBUG - -/***************************************************************************** - * - * Allocate a basic block but don't append it to the current BB list. - */ - -BasicBlock* Compiler::bbNewBasicBlock(BBjumpKinds jumpKind) -{ - BasicBlock* block; - - /* Allocate the block descriptor and zero it out */ - assert(fgSafeBasicBlockCreation); - - block = new (this, CMK_BasicBlock) BasicBlock; - -#if MEASURE_BLOCK_SIZE - BasicBlock::s_Count += 1; - BasicBlock::s_Size += sizeof(*block); -#endif - -#ifdef DEBUG - // fgLookupBB() is invalid until fgInitBBLookup() is called again. - fgBBs = (BasicBlock**)0xCDCD; -#endif - - // TODO-Throughput: The following memset is pretty expensive - do something else? - // Note that some fields have to be initialized to 0 (like bbFPStateX87) - memset(block, 0, sizeof(*block)); - - // scopeInfo needs to be able to differentiate between blocks which - // correspond to some instrs (and so may have some LocalVarInfo - // boundaries), or have been inserted by the JIT - block->bbCodeOffs = BAD_IL_OFFSET; - block->bbCodeOffsEnd = BAD_IL_OFFSET; - - /* Give the block a number, set the ancestor count and weight */ - - ++fgBBcount; - - if (compIsForInlining()) - { - block->bbNum = ++impInlineInfo->InlinerCompiler->fgBBNumMax; - } - else - { - block->bbNum = ++fgBBNumMax; - } - -#ifndef LEGACY_BACKEND - if (compRationalIRForm) - { - block->bbFlags |= BBF_IS_LIR; - } -#endif // !LEGACY_BACKEND - - block->bbRefs = 1; - block->bbWeight = BB_UNITY_WEIGHT; - - block->bbStkTempsIn = NO_BASE_TMP; - block->bbStkTempsOut = NO_BASE_TMP; - - block->bbEntryState = nullptr; - - /* Record the jump kind in the block */ - - block->bbJumpKind = jumpKind; - - if (jumpKind == BBJ_THROW) - { - block->bbSetRunRarely(); - } - -#ifdef DEBUG - if (verbose) - { - printf("New Basic Block BB%02u [%p] created.\n", block->bbNum, dspPtr(block)); - } -#endif - - // We will give all the blocks var sets after the number of tracked variables - // is determined and frozen. After that, if we dynamically create a basic block, - // we will initialize its var sets. - if (fgBBVarSetsInited) - { - VarSetOps::AssignNoCopy(this, block->bbVarUse, VarSetOps::MakeEmpty(this)); - VarSetOps::AssignNoCopy(this, block->bbVarDef, VarSetOps::MakeEmpty(this)); - VarSetOps::AssignNoCopy(this, block->bbLiveIn, VarSetOps::MakeEmpty(this)); - VarSetOps::AssignNoCopy(this, block->bbLiveOut, VarSetOps::MakeEmpty(this)); - VarSetOps::AssignNoCopy(this, block->bbScope, VarSetOps::MakeEmpty(this)); - } - else - { - VarSetOps::AssignNoCopy(this, block->bbVarUse, VarSetOps::UninitVal()); - VarSetOps::AssignNoCopy(this, block->bbVarDef, VarSetOps::UninitVal()); - VarSetOps::AssignNoCopy(this, block->bbLiveIn, VarSetOps::UninitVal()); - VarSetOps::AssignNoCopy(this, block->bbLiveOut, VarSetOps::UninitVal()); - VarSetOps::AssignNoCopy(this, block->bbScope, VarSetOps::UninitVal()); - } - - block->bbMemoryUse = emptyMemoryKindSet; - block->bbMemoryDef = emptyMemoryKindSet; - block->bbMemoryLiveIn = emptyMemoryKindSet; - block->bbMemoryLiveOut = emptyMemoryKindSet; - - for (MemoryKind memoryKind : allMemoryKinds()) - { - block->bbMemorySsaPhiFunc[memoryKind] = nullptr; - block->bbMemorySsaNumIn[memoryKind] = 0; - block->bbMemorySsaNumOut[memoryKind] = 0; - } - - // Make sure we reserve a NOT_IN_LOOP value that isn't a legal table index. - static_assert_no_msg(MAX_LOOP_NUM < BasicBlock::NOT_IN_LOOP); - - block->bbNatLoopNum = BasicBlock::NOT_IN_LOOP; - - return block; -} - -//------------------------------------------------------------------------------ -// containsStatement - return true if the block contains the given statement -//------------------------------------------------------------------------------ - -bool BasicBlock::containsStatement(GenTree* statement) -{ - assert(statement->gtOper == GT_STMT); - - GenTree* curr = bbTreeList; - do - { - if (curr == statement) - { - break; - } - curr = curr->gtNext; - } while (curr); - return curr != nullptr; -} - -GenTreeStmt* BasicBlock::FirstNonPhiDef() -{ - GenTreePtr stmt = bbTreeList; - if (stmt == nullptr) - { - return nullptr; - } - GenTreePtr tree = stmt->gtStmt.gtStmtExpr; - while ((tree->OperGet() == GT_ASG && tree->gtOp.gtOp2->OperGet() == GT_PHI) || - (tree->OperGet() == GT_STORE_LCL_VAR && tree->gtOp.gtOp1->OperGet() == GT_PHI)) - { - stmt = stmt->gtNext; - if (stmt == nullptr) - { - return nullptr; - } - tree = stmt->gtStmt.gtStmtExpr; - } - return stmt->AsStmt(); -} - -GenTreePtr BasicBlock::FirstNonPhiDefOrCatchArgAsg() -{ - GenTreePtr stmt = FirstNonPhiDef(); - if (stmt == nullptr) - { - return nullptr; - } - GenTreePtr tree = stmt->gtStmt.gtStmtExpr; - if ((tree->OperGet() == GT_ASG && tree->gtOp.gtOp2->OperGet() == GT_CATCH_ARG) || - (tree->OperGet() == GT_STORE_LCL_VAR && tree->gtOp.gtOp1->OperGet() == GT_CATCH_ARG)) - { - stmt = stmt->gtNext; - } - return stmt; -} - -/***************************************************************************** - * - * Mark a block as rarely run, we also don't want to have a loop in a - * rarely run block, and we set it's weight to zero. - */ - -void BasicBlock::bbSetRunRarely() -{ - setBBWeight(BB_ZERO_WEIGHT); - if (bbWeight == BB_ZERO_WEIGHT) - { - bbFlags |= BBF_RUN_RARELY; // This block is never/rarely run - } -} - -/***************************************************************************** - * - * Can a BasicBlock be inserted after this without altering the flowgraph - */ - -bool BasicBlock::bbFallsThrough() -{ - switch (bbJumpKind) - { - - case BBJ_THROW: - case BBJ_EHFINALLYRET: - case BBJ_EHFILTERRET: - case BBJ_EHCATCHRET: - case BBJ_RETURN: - case BBJ_ALWAYS: - case BBJ_LEAVE: - case BBJ_SWITCH: - return false; - - case BBJ_NONE: - case BBJ_COND: - return true; - - case BBJ_CALLFINALLY: - return ((bbFlags & BBF_RETLESS_CALL) == 0); - - default: - assert(!"Unknown bbJumpKind in bbFallsThrough()"); - return true; - } -} - -unsigned BasicBlock::NumSucc(Compiler* comp) -{ - // As described in the spec comment of NumSucc at its declaration, whether "comp" is null determines - // whether NumSucc and GetSucc yield successors of finally blocks. - - switch (bbJumpKind) - { - - case BBJ_THROW: - case BBJ_RETURN: - return 0; - - case BBJ_EHFILTERRET: - if (comp == nullptr) - { - return 0; - } - else - { - return 1; - } - - case BBJ_EHFINALLYRET: - { - if (comp == nullptr) - { - return 0; - } - else - { - // The first block of the handler is labelled with the catch type. - BasicBlock* hndBeg = comp->fgFirstBlockOfHandler(this); - if (hndBeg->bbCatchTyp == BBCT_FINALLY) - { - return comp->fgNSuccsOfFinallyRet(this); - } - else - { - assert(hndBeg->bbCatchTyp == BBCT_FAULT); // We can only BBJ_EHFINALLYRET from FINALLY and FAULT. - // A FAULT block has no successors. - return 0; - } - } - } - case BBJ_CALLFINALLY: - case BBJ_ALWAYS: - case BBJ_EHCATCHRET: - case BBJ_LEAVE: - case BBJ_NONE: - return 1; - case BBJ_COND: - if (bbJumpDest == bbNext) - { - return 1; - } - else - { - return 2; - } - case BBJ_SWITCH: - if (comp == nullptr) - { - return bbJumpSwt->bbsCount; - } - else - { - Compiler::SwitchUniqueSuccSet sd = comp->GetDescriptorForSwitch(this); - return sd.numDistinctSuccs; - } - - default: - unreached(); - } -} - -BasicBlock* BasicBlock::GetSucc(unsigned i, Compiler* comp) -{ - // As described in the spec comment of GetSucc at its declaration, whether "comp" is null determines - // whether NumSucc and GetSucc yield successors of finally blocks. - - assert(i < NumSucc(comp)); // Index bounds check. - // printf("bbjk=%d\n", bbJumpKind); - switch (bbJumpKind) - { - - case BBJ_THROW: - case BBJ_RETURN: - unreached(); // Should have been covered by assert above. - - case BBJ_EHFILTERRET: - { - assert(comp != nullptr); // Or else we're not looking for successors. - BasicBlock* result = comp->fgFirstBlockOfHandler(this); - noway_assert(result == bbJumpDest); - // Handler is the (sole) normal successor of the filter. - return result; - } - - case BBJ_EHFINALLYRET: - return comp->fgSuccOfFinallyRet(this, i); - - case BBJ_CALLFINALLY: - case BBJ_ALWAYS: - case BBJ_EHCATCHRET: - case BBJ_LEAVE: - return bbJumpDest; - - case BBJ_NONE: - return bbNext; - case BBJ_COND: - if (i == 0) - { - return bbNext; - } - else - { - assert(i == 1); - return bbJumpDest; - }; - case BBJ_SWITCH: - if (comp == nullptr) - { - assert(i < bbJumpSwt->bbsCount); // Range check. - return bbJumpSwt->bbsDstTab[i]; - } - else - { - // Remove duplicates. - Compiler::SwitchUniqueSuccSet sd = comp->GetDescriptorForSwitch(this); - assert(i < sd.numDistinctSuccs); // Range check. - return sd.nonDuplicates[i]; - } - - default: - unreached(); - } -} - // ------------------------------------------------------------------------- // IsRegOptional: Returns true if this gentree node is marked by lowering to // indicate that codegen can still generate code even if it wasn't allocated @@ -17403,3 +17019,68 @@ regMaskTP ReturnTypeDesc::GetABIReturnRegs() return resultMask; } + +#ifndef LEGACY_BACKEND + +//------------------------------------------------------------------------ +// The following functions manage the gtRsvdRegs set of temporary registers +// created by LSRA during code generation. + +//------------------------------------------------------------------------ +// AvailableTempRegCount: return the number of available temporary registers in the (optional) given set +// (typically, RBM_ALLINT or RBM_ALLFLOAT). +// +// Arguments: +// mask - (optional) Check for available temporary registers only in this set. +// +// Return Value: +// Count of available temporary registers in given set. +// +unsigned GenTree::AvailableTempRegCount(regMaskTP mask /* = (regMaskTP)-1 */) const +{ + return genCountBits(gtRsvdRegs & mask); +} + +//------------------------------------------------------------------------ +// GetSingleTempReg: There is expected to be exactly one available temporary register +// in the given mask in the gtRsvdRegs set. Get that register. No future calls to get +// a temporary register are expected. Removes the register from the set, but only in +// DEBUG to avoid doing unnecessary work in non-DEBUG builds. +// +// Arguments: +// mask - (optional) Get an available temporary register only in this set. +// +// Return Value: +// Available temporary register in given mask. +// +regNumber GenTree::GetSingleTempReg(regMaskTP mask /* = (regMaskTP)-1 */) +{ + regMaskTP availableSet = gtRsvdRegs & mask; + assert(genCountBits(availableSet) == 1); + regNumber tempReg = genRegNumFromMask(availableSet); + INDEBUG(gtRsvdRegs &= ~availableSet;) // Remove the register from the set, so it can't be used again. + return tempReg; +} + +//------------------------------------------------------------------------ +// ExtractTempReg: Find the lowest number temporary register from the gtRsvdRegs set +// that is also in the optional given mask (typically, RBM_ALLINT or RBM_ALLFLOAT), +// and return it. Remove this register from the temporary register set, so it won't +// be returned again. +// +// Arguments: +// mask - (optional) Extract an available temporary register only in this set. +// +// Return Value: +// Available temporary register in given mask. +// +regNumber GenTree::ExtractTempReg(regMaskTP mask /* = (regMaskTP)-1 */) +{ + regMaskTP availableSet = gtRsvdRegs & mask; + assert(genCountBits(availableSet) >= 1); + regMaskTP tempRegMask = genFindLowestBit(availableSet); + gtRsvdRegs &= ~tempRegMask; + return genRegNumFromMask(tempRegMask); +} + +#endif // !LEGACY_BACKEND
\ No newline at end of file |