[llvm] [AMDGPU] Refine GCNHazardRecognizer hasHazard() (PR #138841)
Carl Ritson via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 9 01:52:50 PDT 2025
================
@@ -441,42 +441,96 @@ using IsExpiredFn = function_ref<bool(const MachineInstr &, int WaitStates)>;
using GetNumWaitStatesFn = function_ref<unsigned int(const MachineInstr &)>;
// Search for a hazard in a block and its predecessors.
+// StateT must implement getHashValue() and isEqual().
template <typename StateT>
static bool
-hasHazard(StateT State,
+hasHazard(StateT InitialState,
function_ref<HazardFnResult(StateT &, const MachineInstr &)> IsHazard,
function_ref<void(StateT &, const MachineInstr &)> UpdateState,
- const MachineBasicBlock *MBB,
- MachineBasicBlock::const_reverse_instr_iterator I,
- DenseSet<const MachineBasicBlock *> &Visited) {
- for (auto E = MBB->instr_rend(); I != E; ++I) {
- // No need to look at parent BUNDLE instructions.
- if (I->isBundle())
- continue;
-
- switch (IsHazard(State, *I)) {
- case HazardFound:
- return true;
- case HazardExpired:
- return false;
- default:
- // Continue search
- break;
+ const MachineBasicBlock *InitialMBB,
+ MachineBasicBlock::const_reverse_instr_iterator InitialI) {
+ SmallVector<std::pair<const MachineBasicBlock *, unsigned>> Worklist;
+ SmallDenseSet<std::pair<const MachineBasicBlock *, unsigned>> Visited;
+ SmallVector<std::pair<unsigned, unsigned>, 1> Collisions;
+ SmallDenseMap<unsigned, unsigned> StateHash2Idx;
+ SmallVector<StateT> States;
+
+ // States contains a vector of unique state structures.
+ // StateT is hashed via getHashValue() and StateHash2Idx maps each hash
+ // to an index in the States vector.
+ // In the unlikely event of a hash collision the Collision vector provides
+ // additional hash to index associations which must be retrieved by a linear
+ // scan.
+
+ // Retrieve unique constant index for a StateT structure in the States vector.
+ auto ResolveStateIdx = [&](const StateT State) {
+ unsigned StateHash = State.getHashValue();
+ unsigned StateIdx;
+ if (!StateHash2Idx.contains(StateHash)) {
+ StateIdx = States.size();
+ States.push_back(State);
+ StateHash2Idx[StateHash] = StateIdx;
+ } else {
+ StateIdx = StateHash2Idx[StateHash];
+ if (LLVM_UNLIKELY(!StateT::isEqual(State, States[StateIdx]))) {
+ // Hash collision
+ auto Collision = llvm::find_if(Collisions, [&](auto &C) {
+ return C.first == StateHash &&
+ StateT::isEqual(State, States[C.second]);
+ });
+ if (Collision != Collisions.end()) {
+ StateIdx = Collision->second;
+ } else {
+ StateIdx = States.size();
+ States.push_back(State);
+ Collisions.emplace_back(StateHash, StateIdx);
+ }
+ }
}
+ return StateIdx;
+ };
- if (I->isInlineAsm() || I->isMetaInstruction())
- continue;
+ const MachineBasicBlock *MBB = InitialMBB;
+ StateT State = InitialState;
+ auto I = InitialI;
- UpdateState(State, *I);
- }
+ for (;;) {
+ bool Expired = false;
+ for (auto E = MBB->instr_rend(); I != E; ++I) {
+ // No need to look at parent BUNDLE instructions.
+ if (I->isBundle())
+ continue;
- for (MachineBasicBlock *Pred : MBB->predecessors()) {
- if (!Visited.insert(Pred).second)
- continue;
+ auto Result = IsHazard(State, *I);
+ if (Result == HazardFound)
+ return true;
+ if (Result == HazardExpired) {
+ Expired = true;
+ break;
+ }
- if (hasHazard(State, IsHazard, UpdateState, Pred, Pred->instr_rbegin(),
- Visited))
- return true;
+ if (I->isInlineAsm() || I->isMetaInstruction())
+ continue;
+
+ UpdateState(State, *I);
+ }
+
+ if (!Expired) {
+ unsigned StateIdx = ResolveStateIdx(State);
+ for (MachineBasicBlock *Pred : MBB->predecessors()) {
+ if (!Visited.insert(std::pair(Pred, StateIdx)).second)
+ continue;
+ Worklist.emplace_back(Pred, StateIdx);
----------------
perlfu wrote:
Done
https://github.com/llvm/llvm-project/pull/138841
More information about the llvm-commits
mailing list