Struct spirt::print::Plan

source ·
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 Nodes 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 OpNames across all versions.

That is, each AttrSet maps to one of the SPIR-V OpNames 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. different Types/Consts/etc. can’t use the same AttrSet)
  • in each version using an AttrSet, no other AttrSets are used that “claim” the same SPIR-V OpName
  • an AttrSet “claims” the same SPIR-V OpName 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 AttrSets, 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 OpNames 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>

source

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.

source

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).

source

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.

source

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

fn use_node<D: Visit>(&mut self, node: Node, node_def: &'a D)
where NodeDef<'a>: From<&'a D>,

Add node 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<'_>

source

pub fn pretty_print(&self) -> Versions<FragmentPostLayout>

Print the whole Plan to a Versions<pretty::Fragment> and perform layout on its pretty::Fragments.

The resulting Versions<pretty::FragmentPostLayout> value supports fmt::Display for convenience, but also more specific methods (e.g. HTML output).

source

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).

source§

impl Plan<'_>

source

fn print_all_nodes_and_or_root( &self, printer: &Printer<'_>, print_all_nodes: bool, print_root: bool ) -> Versions<Fragment>

Trait Implementations§

source§

impl Print for Plan<'_>

§

type Output = Versions<Fragment>

source§

fn print(&self, printer: &Printer<'_>) -> Versions<Fragment>

source§

impl<'a> Visitor<'a> for Plan<'a>

source§

fn visit_attr_set_use(&mut self, attrs: AttrSet)

source§

fn visit_type_use(&mut self, ty: Type)

source§

fn visit_const_use(&mut self, ct: Const)

source§

fn visit_data_inst_form_use(&mut self, data_inst_form: DataInstForm)

source§

fn visit_global_var_use(&mut self, gv: GlobalVar)

source§

fn visit_func_use(&mut self, func: Func)

source§

fn visit_module(&mut self, module: &'a Module)

source§

fn visit_module_dialect(&mut self, dialect: &'a ModuleDialect)

source§

fn visit_module_debug_info(&mut self, debug_info: &'a ModuleDebugInfo)

source§

fn visit_attr(&mut self, attr: &'a Attr)

source§

fn visit_const_def(&mut self, ct_def: &'a ConstDef)

source§

fn visit_global_var_decl(&mut self, gv_decl: &'a GlobalVarDecl)

source§

fn visit_func_decl(&mut self, func_decl: &'a FuncDecl)

source§

fn visit_value_use(&mut self, v: &'a Value)

source§

fn visit_spv_dialect(&mut self, _dialect: &Dialect)

source§

fn visit_spv_module_debug_info(&mut self, _debug_info: &ModuleDebugInfo)

source§

fn visit_import(&mut self, _import: &Import)

source§

fn visit_attr_set_def(&mut self, attrs_def: &'a AttrSetDef)

source§

fn visit_type_def(&mut self, ty_def: &'a TypeDef)

source§

fn visit_control_region_def( &mut self, func_at_control_region: FuncAt<'a, ControlRegion> )

source§

fn visit_control_node_def( &mut self, func_at_control_node: FuncAt<'a, ControlNode> )

source§

fn visit_data_inst_def(&mut self, data_inst_def: &'a DataInstDef)

source§

fn visit_data_inst_form_def(&mut self, data_inst_form_def: &'a DataInstFormDef)

Auto Trait Implementations§

§

impl<'a> !RefUnwindSafe for Plan<'a>

§

impl<'a> !Send for Plan<'a>

§

impl<'a> !Sync for Plan<'a>

§

impl<'a> Unpin for Plan<'a>

§

impl<'a> !UnwindSafe for Plan<'a>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.