//
class BlockCountInstrumentor : public Instrumentor
{
+private:
+ BasicBlock* m_entryBlock;
+
public:
- BlockCountInstrumentor(Compiler* comp) : Instrumentor(comp)
+ BlockCountInstrumentor(Compiler* comp) : Instrumentor(comp), m_entryBlock(nullptr)
{
}
bool ShouldProcess(BasicBlock* block) override
schema.push_back(schemaElem);
m_schemaCount++;
+
+ // If this is the entry block, remember it for later.
+ // Note it might not be fgFirstBB, if we have a scratchBB.
+ //
+ if (offset == 0)
+ {
+ assert(m_entryBlock == nullptr);
+ m_entryBlock = block;
+ }
}
//------------------------------------------------------------------------
// Find the address of the entry block's counter.
//
- BasicBlock* const block = m_comp->fgFirstBB;
- const int firstSchemaIndex = block->bbCountSchemaIndex;
- assert(block->bbCodeOffs == (IL_OFFSET)schema[firstSchemaIndex].ILOffset);
+ assert(m_entryBlock != nullptr);
+ assert(m_entryBlock->bbCodeOffs == 0);
+
+ const int firstSchemaIndex = (int)m_entryBlock->bbCountSchemaIndex;
+ assert((IL_OFFSET)schema[firstSchemaIndex].ILOffset == 0);
assert(schema[firstSchemaIndex].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::BasicBlockIntCount);
- size_t addrOfFirstExecutionCount = (size_t)(schema[firstSchemaIndex].Offset + profileMemory);
+
+ const size_t addrOfFirstExecutionCount = (size_t)(schema[firstSchemaIndex].Offset + profileMemory);
GenTree* arg;
arg = m_comp->gtNewIconEmbMethHndNode(info.compMethodHnd);
}
+ // We want to call CORINFO_HELP_BBT_FCN_ENTER just one time,
+ // the first time this method is called. So make the call conditional
+ // on the entry block's profile count.
+ //
GenTreeCall::Use* args = m_comp->gtNewCallArgs(arg);
GenTree* call = m_comp->gtNewHelperCallNode(CORINFO_HELP_BBT_FCN_ENTER, TYP_VOID, args);
// Read Basic-Block count value
+ //
GenTree* valueNode = m_comp->gtNewIndOfIconHandleNode(TYP_INT, addrOfFirstExecutionCount, GTF_ICON_BBC_PTR, false);
// Compare Basic-Block count value against zero
+ //
GenTree* relop = m_comp->gtNewOperNode(GT_NE, TYP_INT, valueNode, m_comp->gtNewIconNode(0, TYP_INT));
GenTree* colon = new (m_comp, GT_COLON) GenTreeColon(TYP_VOID, m_comp->gtNewNothingNode(), call);
GenTree* cond = m_comp->gtNewQmarkNode(TYP_VOID, relop, colon);
Statement* stmt = m_comp->gtNewStmt(cond);
+ // Add this check into the scratch block entry so we only do the check once per call.
+ // If we put it in block we may be putting it inside a loop.
+ //
m_comp->fgEnsureFirstBBisScratch();
- m_comp->fgInsertStmtAtEnd(block, stmt);
+ m_comp->fgInsertStmtAtEnd(m_comp->fgFirstBB, stmt);
}
//------------------------------------------------------------------------