2026-07-31 15:03:26 +01:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: MTask graph for multi-threaded ordering
|
|
|
|
|
//
|
|
|
|
|
// Code available from: https://verilator.org
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
|
|
|
|
// This program is free software; you can redistribute it and/or modify it
|
|
|
|
|
// under the terms of either the GNU Lesser General Public License Version 3
|
|
|
|
|
// or the Perl Artistic License Version 2.0.
|
|
|
|
|
// SPDX-FileCopyrightText: 2003-2026 Wilson Snyder
|
|
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
|
|
|
|
// LogicMTask and MTaskEdge are the vertex and edge of the mtask
|
|
|
|
|
// graph built and coarsened by the multi-threaded partitioner (see
|
|
|
|
|
// V3OrderParallel.cpp). They are independent of the partitioner's merge
|
|
|
|
|
// candidate machinery: any auxiliary data the algorithms need is attached
|
|
|
|
|
// externally via the vertex/edge user pointers.
|
|
|
|
|
//
|
2026-08-17 23:14:52 +02:00
|
|
|
// OrderMTaskGraph maintains the critical paths of the MTasks, and the ones
|
|
|
|
|
// cached in the edge heaps, as the graph is mutated via 'addEdge' and
|
|
|
|
|
// 'mergeMTasks'.
|
2026-08-03 17:00:31 +01:00
|
|
|
//
|
2026-07-31 15:03:26 +01:00
|
|
|
//*************************************************************************
|
|
|
|
|
|
|
|
|
|
#ifndef VERILATOR_V3ORDERMTASKGRAPH_H_
|
|
|
|
|
#define VERILATOR_V3ORDERMTASKGRAPH_H_
|
|
|
|
|
|
|
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
|
|
|
|
|
|
|
|
|
#include "V3Graph.h"
|
|
|
|
|
#include "V3OrderMoveGraph.h"
|
|
|
|
|
#include "V3PairingHeap.h"
|
2026-08-17 23:14:52 +02:00
|
|
|
#include "V3PoolAllocator.h"
|
2026-07-31 15:03:26 +01:00
|
|
|
|
|
|
|
|
#include <array>
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <sstream>
|
|
|
|
|
#include <unordered_set>
|
|
|
|
|
|
|
|
|
|
class LogicMTask;
|
2026-08-03 17:00:31 +01:00
|
|
|
class OrderMTaskGraph;
|
2026-07-31 15:03:26 +01:00
|
|
|
|
|
|
|
|
//=============================================================================
|
2026-08-17 23:14:52 +02:00
|
|
|
// MTaskEdge graph edges are stored in a PairingHeap in each LogicMTask they
|
|
|
|
|
// connect to, sorted by critical path through that edge (and id for stability).
|
2026-07-31 15:03:26 +01:00
|
|
|
|
|
|
|
|
struct EdgeKey final {
|
2026-08-17 23:14:52 +02:00
|
|
|
uint64_t m_cp; // The inclusive critical path of the further MTask of the edge
|
|
|
|
|
uint32_t m_id; // The ID of the further MTask, for stable comparison
|
|
|
|
|
void increase(uint64_t cp) {
|
|
|
|
|
UDEBUGONLY(UASSERT(cp >= m_cp, "Must increase"););
|
|
|
|
|
m_cp = cp;
|
2026-07-31 15:03:26 +01:00
|
|
|
}
|
2026-08-17 23:14:52 +02:00
|
|
|
// Sort first by critical path, then by ID
|
2026-07-31 15:03:26 +01:00
|
|
|
bool operator<(const EdgeKey& other) const {
|
2026-08-17 23:14:52 +02:00
|
|
|
if (m_cp != other.m_cp) return m_cp < other.m_cp;
|
2026-07-31 15:03:26 +01:00
|
|
|
return m_id < other.m_id;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using EdgeHeap = PairingHeap<EdgeKey>;
|
|
|
|
|
|
2026-08-17 23:14:52 +02:00
|
|
|
//=============================================================================
|
|
|
|
|
// LogicMTasks are stored in a PairingHeap during critical path update propagation.
|
|
|
|
|
|
|
|
|
|
struct PropagatePendingKey final {
|
|
|
|
|
uint64_t m_increment; // The amount the critical path of the MTask will grow by
|
|
|
|
|
uint32_t m_id; // The ID of the MTask, for stable comparison
|
|
|
|
|
LogicMTask* m_mtaskp; // The MTask the heap entry corresponds to
|
|
|
|
|
void increase(uint64_t increment) {
|
|
|
|
|
UDEBUGONLY(UASSERT(increment >= m_increment, "Must increase"););
|
|
|
|
|
m_increment = increment;
|
|
|
|
|
}
|
|
|
|
|
// Sort first by increment, then by ID
|
|
|
|
|
bool operator<(const PropagatePendingKey& other) const {
|
|
|
|
|
if (m_increment != other.m_increment) return m_increment < other.m_increment;
|
|
|
|
|
return m_id < other.m_id;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using PropagatePendingHeap = PairingHeap<PropagatePendingKey>;
|
|
|
|
|
|
2026-07-31 15:03:26 +01:00
|
|
|
//=============================================================================
|
|
|
|
|
// GraphEdge for the MTask graph
|
|
|
|
|
|
|
|
|
|
class MTaskEdge final : public V3GraphEdge {
|
|
|
|
|
VL_RTTI_IMPL(MTaskEdge, V3GraphEdge)
|
|
|
|
|
|
|
|
|
|
friend class LogicMTask;
|
2026-08-17 23:14:52 +02:00
|
|
|
friend class OrderMTaskGraph;
|
2026-07-31 15:03:26 +01:00
|
|
|
|
|
|
|
|
// MEMBERS
|
|
|
|
|
// This edge can be in 2 EdgeHeaps, one forward and one reverse. We allocate the heap nodes
|
|
|
|
|
// directly within the edge as they are always required and this makes association cheap.
|
|
|
|
|
std::array<EdgeHeap::Node, GraphWay::NUM_WAYS> m_edgeHeapNode;
|
|
|
|
|
|
2026-08-17 23:14:52 +02:00
|
|
|
// CONSTRUCTORS
|
|
|
|
|
// Private, so edges can only be created via OrderMTaskGraph, which also updates the critical
|
|
|
|
|
// paths on graph mutation.
|
|
|
|
|
inline MTaskEdge(OrderMTaskGraph* graphp, LogicMTask* fromp, LogicMTask* top);
|
2026-07-31 15:03:26 +01:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
VL_UNCOPYABLE(MTaskEdge);
|
|
|
|
|
VL_UNMOVABLE(MTaskEdge);
|
|
|
|
|
|
|
|
|
|
// METHODS
|
|
|
|
|
template <GraphWay::en N_Way>
|
|
|
|
|
inline LogicMTask* furtherMTaskp() const;
|
|
|
|
|
inline LogicMTask* fromMTaskp() const;
|
|
|
|
|
inline LogicMTask* toMTaskp() const;
|
|
|
|
|
|
2026-08-17 23:14:52 +02:00
|
|
|
uint64_t cachedCp(GraphWay way) const { return m_edgeHeapNode[way].key().m_cp; }
|
|
|
|
|
uint32_t cachedId(GraphWay way) const { return m_edgeHeapNode[way].key().m_id; }
|
2026-07-31 15:03:26 +01:00
|
|
|
// Convert from the address of the m_edgeHeapNode[way] in an MTaskEdge back to the MTaskEdge
|
|
|
|
|
static const MTaskEdge* toMTaskEdge(GraphWay way, const EdgeHeap::Node* nodep) {
|
|
|
|
|
const size_t offset = VL_OFFSETOF(MTaskEdge, m_edgeHeapNode[way]);
|
|
|
|
|
return reinterpret_cast<const MTaskEdge*>(reinterpret_cast<uintptr_t>(nodep) - offset);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
|
// LogicMTask
|
|
|
|
|
|
|
|
|
|
class LogicMTask final : public V3GraphVertex {
|
|
|
|
|
VL_RTTI_IMPL(LogicMTask, V3GraphVertex)
|
|
|
|
|
|
2026-08-17 23:14:52 +02:00
|
|
|
friend class MTaskEdge;
|
|
|
|
|
friend class OrderMTaskGraph;
|
2026-07-31 15:03:26 +01:00
|
|
|
|
|
|
|
|
// MEMBERS
|
|
|
|
|
|
|
|
|
|
// List of OrderMoveVertex's assigned to this mtask. LogicMTask does not own the
|
|
|
|
|
// OrderMoveVertex objects, we merely keep them in a list here.
|
|
|
|
|
OrderMoveVertex::List m_mVertices;
|
|
|
|
|
|
2026-08-17 23:14:52 +02:00
|
|
|
static uint32_t s_nextId; // Next ID number to use
|
|
|
|
|
const uint32_t m_id = s_nextId++; // Unique LogicMTask ID number for stable comparison
|
|
|
|
|
|
2026-07-31 15:03:26 +01:00
|
|
|
// Cost estimate for this LogicMTask, derived from V3InstrCount, in abstract time units.
|
2026-08-03 17:34:44 +01:00
|
|
|
// Cost estimates and critical path lengths are bounded by number of AstNodes * constant,
|
|
|
|
|
// will run out of host memory storing the Ast way before they can overflow.
|
2026-07-31 15:03:26 +01:00
|
|
|
uint64_t m_cost = 0;
|
|
|
|
|
|
2026-08-17 23:14:52 +02:00
|
|
|
// Critical path in each direction: going FORWARD from graph-start to the start of this vertex,
|
|
|
|
|
// and going REVERSE from graph-exit to the end of this vertex. Exclusive of the cost of this
|
|
|
|
|
// vertex itself, see cpInclusive() for the value including it.
|
|
|
|
|
std::array<uint64_t, GraphWay::NUM_WAYS> m_cpExclusive = {0, 0};
|
2026-07-31 15:03:26 +01:00
|
|
|
|
2026-08-17 23:14:52 +02:00
|
|
|
// The MTasks this MTask has an out-edge to, so checking for an existing edge is O(1)
|
|
|
|
|
std::unordered_set<LogicMTask*> m_dependents;
|
|
|
|
|
// Store the out/in edges in a heaps sorted by the critical path length through each edge
|
|
|
|
|
std::array<EdgeHeap, GraphWay::NUM_WAYS> m_edgeHeap;
|
2026-07-31 15:03:26 +01:00
|
|
|
|
|
|
|
|
// Count "generations" which are just operations that scan through the
|
|
|
|
|
// graph. We'll mark each node with the last generation that scanned
|
|
|
|
|
// it. We can use this to avoid recursing through the same node twice
|
|
|
|
|
// while searching for a path.
|
|
|
|
|
uint64_t m_generation = 0;
|
|
|
|
|
|
2026-08-17 23:14:52 +02:00
|
|
|
// Scratch pointer used only by the critical path propagation in OrderMTaskGraph: this MTask's
|
|
|
|
|
// node in the pending heap, or nullptr if this MTask is not pending.
|
|
|
|
|
PropagatePendingHeap::Node* m_propagateHeapNodep = nullptr;
|
2026-07-31 15:03:26 +01:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// CONSTRUCTORS
|
|
|
|
|
LogicMTask(OrderMTaskGraph& graph, OrderMoveVertex* mVtxp) VL_MT_DISABLED;
|
|
|
|
|
VL_UNCOPYABLE(LogicMTask);
|
|
|
|
|
VL_UNMOVABLE(LogicMTask);
|
|
|
|
|
|
2026-08-17 23:14:52 +02:00
|
|
|
// METHODS
|
2026-07-31 15:03:26 +01:00
|
|
|
OrderMoveVertex::List& vertexList() { return m_mVertices; }
|
|
|
|
|
uint32_t id() const { return m_id; }
|
|
|
|
|
bool operator<(const LogicMTask& rhs) const { return id() < rhs.id(); }
|
|
|
|
|
|
2026-08-17 23:14:52 +02:00
|
|
|
uint64_t cost() const VL_MT_SAFE { return m_cost; }
|
2026-07-31 15:03:26 +01:00
|
|
|
template <GraphWay::en N_Way>
|
2026-08-17 23:14:52 +02:00
|
|
|
uint64_t cpExclusive() const {
|
|
|
|
|
return m_cpExclusive[N_Way];
|
2026-07-31 15:03:26 +01:00
|
|
|
}
|
|
|
|
|
template <GraphWay::en N_Way>
|
2026-08-17 23:14:52 +02:00
|
|
|
uint64_t cpInclusive() const {
|
|
|
|
|
return m_cpExclusive[N_Way] + m_cost;
|
2026-07-31 15:03:26 +01:00
|
|
|
}
|
2026-08-17 23:14:52 +02:00
|
|
|
// The critical path of this MTask without considering the given edge.
|
2026-07-31 15:03:26 +01:00
|
|
|
template <GraphWay::en N_Way>
|
2026-08-17 23:14:52 +02:00
|
|
|
uint64_t cpExclusiveWithout(const V3GraphEdge* edgep) const {
|
2026-07-31 15:03:26 +01:00
|
|
|
const GraphWay way{N_Way};
|
|
|
|
|
const GraphWay inv = way.invert();
|
2026-08-17 23:14:52 +02:00
|
|
|
UDEBUGONLY(UASSERT(edgep->furtherp<N_Way>() == this,
|
|
|
|
|
"In cpExclusiveWithout(), 'edgep' must further to 'this'"););
|
|
|
|
|
// At most two edges need to be considered: the critical path, if that is not via 'edgep',
|
|
|
|
|
// or the second-worst path, if the critical path is via 'edgep'.
|
2026-07-31 15:03:26 +01:00
|
|
|
const EdgeHeap& edgeHeap = m_edgeHeap[inv];
|
2026-08-17 23:14:52 +02:00
|
|
|
// Pick up the critical path edge
|
2026-07-31 15:03:26 +01:00
|
|
|
const EdgeHeap::Node* const maxp = edgeHeap.max();
|
2026-08-17 23:14:52 +02:00
|
|
|
UDEBUGONLY(UASSERT(maxp, "Edge not in heap"););
|
|
|
|
|
// If 'edgep' is not the critical path edge, return its critical path
|
|
|
|
|
if (MTaskEdge::toMTaskEdge(inv, maxp) != edgep) return maxp->key().m_cp;
|
|
|
|
|
// Otherwise return the second-worst path, if there is one
|
2026-07-31 15:03:26 +01:00
|
|
|
const EdgeHeap::Node* const secp = edgeHeap.secondMax();
|
|
|
|
|
if (!secp) return 0;
|
2026-08-17 23:14:52 +02:00
|
|
|
return secp->key().m_cp;
|
2026-07-31 15:03:26 +01:00
|
|
|
}
|
|
|
|
|
|
2026-08-17 23:14:52 +02:00
|
|
|
bool hasEdgeTo(LogicMTask* dependentp) const { return m_dependents.count(dependentp); }
|
2026-07-31 15:03:26 +01:00
|
|
|
|
|
|
|
|
// For Graphviz dumps only
|
|
|
|
|
std::string name() const override VL_MT_STABLE {
|
|
|
|
|
std::ostringstream out;
|
|
|
|
|
out << "mt" << m_id //
|
2026-08-17 23:14:52 +02:00
|
|
|
<< " | cpFwd " << m_cpExclusive[GraphWay::FORWARD] //
|
|
|
|
|
<< " | cost " << cost() //
|
|
|
|
|
<< " | cpRev " << m_cpExclusive[GraphWay::REVERSE];
|
2026-07-31 15:03:26 +01:00
|
|
|
return out.str();
|
|
|
|
|
}
|
2026-08-03 17:00:31 +01:00
|
|
|
|
|
|
|
|
private:
|
2026-08-17 23:14:52 +02:00
|
|
|
// Following only used by OrderMTaskGraph, which maintains cached CPs and graph invariants.
|
2026-08-03 17:00:31 +01:00
|
|
|
|
2026-08-17 23:14:52 +02:00
|
|
|
template <GraphWay::en N_Way>
|
|
|
|
|
uint64_t cpExclusiveFromEdges() const {
|
|
|
|
|
constexpr GraphWay inv = GraphWay{N_Way}.invert();
|
|
|
|
|
const EdgeHeap::Node* const maxp = m_edgeHeap[inv].max();
|
|
|
|
|
return maxp ? maxp->key().m_cp : 0;
|
|
|
|
|
}
|
|
|
|
|
template <GraphWay::en N_Way>
|
|
|
|
|
void cpExclusive(uint64_t cp) {
|
|
|
|
|
m_cpExclusive[N_Way] = cp;
|
2026-08-03 17:00:31 +01:00
|
|
|
}
|
|
|
|
|
|
2026-08-17 23:14:52 +02:00
|
|
|
template <GraphWay::en N_Way>
|
|
|
|
|
void addRelativeEdge(MTaskEdge* edgep) {
|
2026-08-03 17:00:31 +01:00
|
|
|
constexpr GraphWay way{N_Way};
|
2026-08-17 23:14:52 +02:00
|
|
|
constexpr GraphWay inv = way.invert();
|
|
|
|
|
// Add to the edge heap
|
|
|
|
|
LogicMTask* const relativep = edgep->furtherMTaskp<N_Way>();
|
|
|
|
|
// Value is the !way inclusive cp of the relative
|
|
|
|
|
const uint64_t cp = relativep->cpInclusive<inv>();
|
|
|
|
|
m_edgeHeap[way].insert(&edgep->m_edgeHeapNode[way], {cp, relativep->id()});
|
2026-08-03 17:00:31 +01:00
|
|
|
}
|
2026-08-17 23:14:52 +02:00
|
|
|
template <GraphWay::en N_Way>
|
|
|
|
|
void stealRelativeEdge(MTaskEdge* edgep) {
|
2026-08-03 17:00:31 +01:00
|
|
|
constexpr GraphWay way{N_Way};
|
2026-08-17 23:14:52 +02:00
|
|
|
// Make heap node insertable, ruining the heap it is currently in.
|
|
|
|
|
edgep->m_edgeHeapNode[way].yank();
|
|
|
|
|
// Add the edge as new
|
|
|
|
|
addRelativeEdge<N_Way>(edgep);
|
|
|
|
|
}
|
|
|
|
|
template <GraphWay::en N_Way>
|
|
|
|
|
void removeRelativeEdge(MTaskEdge* edgep) {
|
|
|
|
|
constexpr GraphWay way{N_Way};
|
|
|
|
|
// Remove from the edge heap
|
|
|
|
|
m_edgeHeap[way].remove(&edgep->m_edgeHeapNode[way]);
|
2026-08-03 17:00:31 +01:00
|
|
|
}
|
|
|
|
|
|
2026-08-17 23:14:52 +02:00
|
|
|
void addDependent(LogicMTask* dependentp) {
|
|
|
|
|
const bool exists = !m_dependents.emplace(dependentp).second;
|
|
|
|
|
UDEBUGONLY(UASSERT(!exists, "Adding existing dependent"););
|
|
|
|
|
}
|
|
|
|
|
void removeDependent(LogicMTask* dependentp) {
|
|
|
|
|
const size_t removed = m_dependents.erase(dependentp);
|
|
|
|
|
UDEBUGONLY(UASSERT(removed, "Dependent should have been in set"););
|
|
|
|
|
}
|
2026-08-03 17:00:31 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
|
// OrderMTaskGraph
|
|
|
|
|
|
|
|
|
|
// The graph of LogicMTask vertices and MTaskEdge edges, used during multi-threaded scheduling.
|
|
|
|
|
class OrderMTaskGraph final : public V3Graph {
|
2026-08-17 23:14:52 +02:00
|
|
|
// MEMBERS
|
2026-08-03 17:00:31 +01:00
|
|
|
OrderMoveGraph& m_moveGraph; // The OrderMoveGraph this graph is built from
|
|
|
|
|
LogicMTask* const m_entryp; // The singular entry point vertex
|
|
|
|
|
LogicMTask* const m_exitp; // The singular exit point vertex
|
|
|
|
|
|
2026-08-17 23:14:52 +02:00
|
|
|
const bool m_slowAsserts; // Take extra time to validate the graph ('--debug-partition')
|
|
|
|
|
|
|
|
|
|
// Critical path propagation state. Scratch only: the heap is empty, and no MTask is pending,
|
|
|
|
|
// between calls to 'propagate'. The node pool persists to recycle the heap nodes.
|
|
|
|
|
PropagatePendingHeap m_pendingHeap; // Heap of MTasks pending a critical path update
|
|
|
|
|
PoolAllocator<PropagatePendingHeap::Node> m_pendingNodePool; // Allocator for the heap nodes
|
|
|
|
|
|
|
|
|
|
// Generation counter, e.g. for marking the MTasks visited by algorithms
|
|
|
|
|
uint64_t m_currentGeneration = 0;
|
2026-08-03 17:00:31 +01:00
|
|
|
|
|
|
|
|
// CONSTRUCTOR
|
|
|
|
|
explicit OrderMTaskGraph(OrderMoveGraph& moveGraph); // Used by build(), hence private
|
|
|
|
|
VL_UNCOPYABLE(OrderMTaskGraph);
|
|
|
|
|
VL_UNMOVABLE(OrderMTaskGraph);
|
|
|
|
|
|
2026-08-17 23:14:52 +02:00
|
|
|
// METHODS
|
|
|
|
|
|
|
|
|
|
bool pathExistsImpl(LogicMTask* fromp, LogicMTask* top, const MTaskEdge* excludedEdgep);
|
|
|
|
|
|
|
|
|
|
// Bring the critical paths of all MTasks wayward of 'mtaskp' in direction N_Way, and those
|
|
|
|
|
// cached in the edge heaps on the way, up to date. Call after mutating the graph such that
|
|
|
|
|
// only MTasks wayward of 'mtaskp' can have a stale critical path, and the critical path of
|
|
|
|
|
// 'mtaskp' itself is already correct. 'mtaskp' is read, but never modified.
|
|
|
|
|
//
|
|
|
|
|
// Note critical paths can only ever grow: those cached in the edge heaps are heap keys, and a
|
|
|
|
|
// heap key can be increased in place, but not decreased.
|
|
|
|
|
template <GraphWay::en N_Way>
|
|
|
|
|
void propagate(LogicMTask* mtaskp) {
|
|
|
|
|
++m_currentGeneration;
|
|
|
|
|
propagatePush<N_Way>(mtaskp);
|
|
|
|
|
propagateResolve<N_Way>();
|
|
|
|
|
}
|
|
|
|
|
// Push the inclusive critical path of 'mtaskp' onto each of its wayward relatives, and add any
|
|
|
|
|
// relative left with a stale critical path to the pending heap (out of line below)
|
|
|
|
|
template <GraphWay::en N_Way>
|
|
|
|
|
void propagatePush(LogicMTask* mtaskp);
|
|
|
|
|
// Resolve all pending critical path increases (out of line below)
|
|
|
|
|
template <GraphWay::en N_Way>
|
|
|
|
|
void propagateResolve();
|
|
|
|
|
// Part of 'validate'
|
|
|
|
|
template <GraphWay::en N_Way>
|
|
|
|
|
void validateWay() const;
|
|
|
|
|
|
2026-08-03 17:00:31 +01:00
|
|
|
public:
|
|
|
|
|
// ACCESSORS
|
|
|
|
|
OrderMoveGraph& moveGraph() const { return m_moveGraph; }
|
|
|
|
|
LogicMTask* entryp() const { return m_entryp; }
|
|
|
|
|
LogicMTask* exitp() const { return m_exitp; }
|
2026-08-17 23:14:52 +02:00
|
|
|
bool slowAsserts() const { return m_slowAsserts; }
|
2026-08-03 17:00:31 +01:00
|
|
|
|
|
|
|
|
// METHODS
|
|
|
|
|
uint64_t totalCost() const; // O(V), called once
|
|
|
|
|
|
2026-08-17 23:14:52 +02:00
|
|
|
// True if there's a path from 'fromp' to 'top' excluding 'excludedEdgep', false otherwise.
|
|
|
|
|
// 'excludedEdgep' may be nullptr in which case no edge is excluded. If 'excludedEdgep' is
|
|
|
|
|
// non-nullptr it must connect fromp and top.
|
|
|
|
|
bool pathExists(LogicMTask* fromp, LogicMTask* top, const MTaskEdge* excludedEdgep) {
|
|
|
|
|
++m_currentGeneration;
|
|
|
|
|
return pathExistsImpl(fromp, top, excludedEdgep);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add an edge to the graph, update impacted critical paths
|
|
|
|
|
void addEdge(LogicMTask* fromp, LogicMTask* top);
|
|
|
|
|
|
|
|
|
|
// Merge 'donorp' into 'recipientp': move the contents and all edges of 'donorp' onto
|
|
|
|
|
// 'recipientp', update impacted critical paths, then delete 'donorp'. The edge connecting the
|
|
|
|
|
// two (if any) becomes internal to the merged MTask and is deleted, as is one of each pair of
|
|
|
|
|
// edges the two have to a common relative. Note this deletes edges, so the caller must have
|
|
|
|
|
// released any auxiliary data it attached to them via their user pointer.
|
|
|
|
|
void mergeMTasks(LogicMTask* recipientp, LogicMTask* donorp);
|
|
|
|
|
|
2026-08-18 08:50:50 +02:00
|
|
|
// Remove all transitive edges. (This deliberately hides V3Graph::removeTransitiveEdges,
|
|
|
|
|
// which would leave the auxiliary data structures stale.)
|
|
|
|
|
// cppcheck-suppress duplInheritedMember
|
|
|
|
|
void removeTransitiveEdges();
|
|
|
|
|
|
|
|
|
|
// Remove all MTasks holding no logic (except for entry and exit, which are kept even if
|
|
|
|
|
// empty), connecting their predecessors directly to their successors.
|
|
|
|
|
void removeEmptyMTasks();
|
|
|
|
|
|
|
|
|
|
// Do an expensive check that the maintained critical paths, including the ones cached in the
|
|
|
|
|
// edge heaps, match those implied by the current edges of the graph, and that auxiliary data
|
|
|
|
|
// structures are consistent.
|
2026-08-17 23:14:52 +02:00
|
|
|
void validate() const;
|
|
|
|
|
|
2026-08-03 17:00:31 +01:00
|
|
|
// STATIC METHODS
|
|
|
|
|
// Build an MTask graph from 'moveGraph'
|
|
|
|
|
static std::unique_ptr<OrderMTaskGraph> build(OrderMoveGraph& moveGraph) VL_MT_DISABLED;
|
|
|
|
|
// Fix data hazards in the MTask graph
|
|
|
|
|
static void fixDataHazards(OrderMTaskGraph& mtaskGraph) VL_MT_DISABLED;
|
|
|
|
|
// Coarsen the MTask graph by merging MTasks until the given critical-path limit is reached
|
|
|
|
|
static void contract(OrderMTaskGraph& mtaskGraph, uint64_t scoreLimit) VL_MT_DISABLED;
|
|
|
|
|
};
|
|
|
|
|
|
2026-07-31 15:03:26 +01:00
|
|
|
//=============================================================================
|
|
|
|
|
// MTaskEdge method definitions (need the full definition of LogicMTask)
|
|
|
|
|
|
2026-08-17 23:14:52 +02:00
|
|
|
MTaskEdge::MTaskEdge(OrderMTaskGraph* graphp, LogicMTask* fromp, LogicMTask* top)
|
|
|
|
|
: V3GraphEdge{graphp, fromp, top, 1} {
|
|
|
|
|
fromp->addDependent(top);
|
2026-07-31 15:03:26 +01:00
|
|
|
fromp->addRelativeEdge<GraphWay::FORWARD>(this);
|
|
|
|
|
top->addRelativeEdge<GraphWay::REVERSE>(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <GraphWay::en N_Way>
|
|
|
|
|
LogicMTask* MTaskEdge::furtherMTaskp() const {
|
|
|
|
|
return static_cast<LogicMTask*>(this->furtherp<N_Way>());
|
|
|
|
|
}
|
|
|
|
|
LogicMTask* MTaskEdge::fromMTaskp() const { return static_cast<LogicMTask*>(fromp()); }
|
|
|
|
|
LogicMTask* MTaskEdge::toMTaskp() const { return static_cast<LogicMTask*>(top()); }
|
|
|
|
|
|
|
|
|
|
#endif // Guard
|