summaryrefslogtreecommitdiff
path: root/src/jit/gentree.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/gentree.cpp')
-rw-r--r--src/jit/gentree.cpp451
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