pub struct Plan<'a> {
cx: &'a Context,
current_module: Option<&'a Module>,
versions: Vec<PlanVersion<'a>>,
use_counts: IndexMap<Use, usize, BuildHasherDefault<FxHasher>>,
attrs_to_unique_spv_name: FxHashMap<AttrSet, Result<&'a Inst, AmbiguousName>>,
claimed_spv_names: FxHashMap<&'a Inst, Result<AttrSet, AmbiguousName>>,
}
Expand description
“Definitions-before-uses” / “topo-sorted” printing plan.
In order to represent parts of a DAG textually, it first needs to have its
nodes “flattened” into an order (also known as “topo(logical) sorting”),
which Plan
wholly records, before any printing can commence.
Additionally, nodes without a significant identity (i.e. interned ones) may have their separate definition omitted in some cases where printing them inline at their use site(s) is preferred (e.g. when they have a single use).
Once a Plan
contains everything that needs to be printed, calling the
.pretty_print()
method will print all of the nodes
in the Plan
, and its return value can be e.g. formatted with fmt::Display
.
Fields§
§cx: &'a Context
§current_module: Option<&'a Module>
When visiting module-stored nodes, the Module
is needed to map the
Node
to the (per-version) definition, which is then stored in the
(per-version) node_defs
map.
versions: Vec<PlanVersion<'a>>
Versions allow comparing multiple copies of the same e.g. Module
,
with definitions sharing a Node
key being shown together.
Specific Node
s may be present in only a subset of versions, and such
a distinction will be reflected in the output.
For Node
collection, versions.last()
constitutes the “active” one.
use_counts: IndexMap<Use, usize, BuildHasherDefault<FxHasher>>
Merged per-Use
counts across all versions.
That is, each Use
maps to the largest count of that Use
in any version,
as opposed to their sum. This approach avoids pessimizing e.g. inline
printing of interned definitions, which may need the use count to be 1
.
attrs_to_unique_spv_name: FxHashMap<AttrSet, Result<&'a Inst, AmbiguousName>>
Merged per-AttrSet
unique SPIR-V OpName
s across all versions.
That is, each AttrSet
maps to one of the SPIR-V OpName
s contained
within the AttrSet
, as long as these three conditions are met:
- in each version using an
AttrSet
, there is only one use of it (e.g. differentType
s/Const
s/etc. can’t use the sameAttrSet
) - in each version using an
AttrSet
, no otherAttrSet
s are used that “claim” the same SPIR-VOpName
- an
AttrSet
“claims” the same SPIR-VOpName
across all versions using it (with per-version “claiming”, only merged after the fact)
Note that these conditions still allow the same SPIR-V OpName
being
“claimed” by different AttrSet
s, as long as they only show up in
disjoint versions (e.g. GlobalVarDecl
attributes being modified
between versions, but keeping the same OpName
attribute unchanged).
claimed_spv_names: FxHashMap<&'a Inst, Result<AttrSet, AmbiguousName>>
Reverse map of attrs_to_unique_spv_name_imms
, only used during visiting
(i.e. intra-version), to track which SPIR-V OpName
s have been “claimed”
by some AttrSet
and detect conflicts (which are resolved by marking
both overlapping AttrSet
, and the OpName
itself, as ambiguous).
Implementations§
source§impl<'a> Plan<'a>
impl<'a> Plan<'a>
sourcepub fn for_root(
cx: &'a Context,
root: &'a (impl Visit + Print<Output = Fragment>)
) -> Self
pub fn for_root( cx: &'a Context, root: &'a (impl Visit + Print<Output = Fragment>) ) -> Self
Create a Plan
with all of root
’s dependencies, followed by root
itself.
sourcepub fn for_module(module: &'a Module) -> Self
pub fn for_module(module: &'a Module) -> Self
Create a Plan
with all of module
’s contents.
Shorthand for Plan::for_root(module.cx_ref(), module)
.
sourcepub fn for_versions(
cx: &'a Context,
versions: impl IntoIterator<Item = (impl Into<String>, &'a (impl Visit + Print<Output = Fragment> + 'a))>
) -> Self
pub fn for_versions( cx: &'a Context, versions: impl IntoIterator<Item = (impl Into<String>, &'a (impl Visit + Print<Output = Fragment> + 'a))> ) -> Self
Create a Plan
that combines Plan::for_root
from each version.
Each version also has a string, which should contain a descriptive name (e.g. the name of a pass that produced that version).
While the roots (and their dependencies) can be entirely unrelated, the
output won’t be very useful in that case. For ideal results, most of the
same entities (e.g. GlobalVar
or Func
) should be in most versions,
with most of the changes being limited to within their definitions.
sourcefn use_interned(&mut self, interned: CxInterned)
fn use_interned(&mut self, interned: CxInterned)
Add interned
to the plan, after all of its dependencies.
Only the first call recurses into the definition, subsequent calls only update its (internally tracked) “use count”.
source§impl Plan<'_>
impl Plan<'_>
sourcepub fn pretty_print(&self) -> Versions<FragmentPostLayout>
pub fn pretty_print(&self) -> Versions<FragmentPostLayout>
Print the whole Plan
to a Versions<pretty::Fragment>
and perform
layout on its pretty::Fragment
s.
The resulting Versions<pretty::FragmentPostLayout>
value supports
fmt::Display
for convenience, but also more specific methods
(e.g. HTML output).
sourcepub fn pretty_print_deps_and_root_separately(
&self
) -> (Versions<FragmentPostLayout>, Versions<FragmentPostLayout>)
pub fn pretty_print_deps_and_root_separately( &self ) -> (Versions<FragmentPostLayout>, Versions<FragmentPostLayout>)
Like pretty_print
, but separately pretty-printing “root dependencies”
and the “root” itself (useful for nesting pretty-printed SPIR-T elsewhere).