graph

package module
v0.0.0-...-dd67d02 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 19, 2025 License: GPL-3.0 Imports: 2 Imported by: 2

README

graph

CI codecov pre-commit.ci status

Documentation

Index

Constants

View Source
const Unreachable = ^uint(0)

Variables

This section is empty.

Functions

This section is empty.

Types

type ControlFlowGraph

type ControlFlowGraph struct {
	Graph

	// BasicBlockToNodes[i] contains the set of nodes in the original graph that
	// the i-th basic block contains.
	BasicBlockToNodes [][]uint

	// NodeToBasicBlock[i] contains the index of the basic block that the i-th
	// node in the original graph belongs to.
	// NodeToBasicBlock[i] = Unreachable if the original node i is not included
	// in the control flow graph, i.e., it is unreachable from the entry node.
	NodeToBasicBlock []uint
}

type Dfs

type Dfs struct {
	// PreOrder[v] is the index of v in the DFS pre-order traversal.
	PreOrder []uint

	// PreOrderReversed[i] is the node with the i-th index in the preorder.
	PreOrderReversed []uint

	// PostOrder[v] is the index of v in the DFS post-order traversal.
	PostOrder []uint

	// Timeline is a slice of length 2n, where each push and pop operation
	// during the DFS traversal of the stack is recorded.
	//
	// Operations are ordered in chronological order. If Timeline[i] = k,
	// where k in [0, n), then the i-th operation in the traversal was a push
	// operation of the value k. Otherwise, if k in [n, 2n), then it represents
	// a pop of the value k-n.
	Timeline []uint

	// Parent[v] is the parent of v in the DFS spanning tree.
	// The parent of the root of the tree is itself.
	Parent []uint

	// Depth[v] is the depth of v in the DFS spanning tree.
	Depth []uint

	// SubtreeSize[v] is the size of the subtree of v in the DFS spanning tree,
	// including v itself.
	SubtreeSize []uint
}

func (*Dfs) IsAncestor

func (d *Dfs) IsAncestor(ancestor uint, descendant uint) bool

func (*Dfs) IsDeeper

func (d *Dfs) IsDeeper(deeper uint, shallower uint) bool

func (*Dfs) IsStrictAncestor

func (d *Dfs) IsStrictAncestor(ancestor uint, descendant uint) bool

func (*Dfs) IsStrictlyDeeper

func (d *Dfs) IsStrictlyDeeper(deeper uint, shallower uint) bool

func (*Dfs) Subtree

func (d *Dfs) Subtree(v uint) []uint

type DominatorJoinGraph

type DominatorJoinGraph struct {
	DominatorTree
	JoinGraph Graph
}

func (*DominatorJoinGraph) DominatorFrontier

func (g *DominatorJoinGraph) DominatorFrontier(node uint) []uint

Computes the dominator frontier of the provided node in linear time.

Note if your purpose is to compute the dominator frontier of a set of multiple nodes, or the iterated dominator frontier, there are better methods then calling this method multiple times, resulting in a quadratic time. See the IteratedDominatorFrontier method for more information.

For more information, see https://doi.org/10.1145/199448.199464

func (*DominatorJoinGraph) IteratedDominatorFrontier

func (g *DominatorJoinGraph) IteratedDominatorFrontier(nodes []uint) []uint

type DominatorTree

type DominatorTree struct {
	*Graph
	Dfs

	// ImmDom[v] is the immediate dominator of v, and by definition of the
	// dominator tree, ImmDom[v] is the parent of v in the dominator tree.
	//
	// It is assumed that ImmDom[root] = root.
	ImmDom []uint
}

func (*DominatorTree) IsDominatorOf

func (t *DominatorTree) IsDominatorOf(dominator uint, dominated uint) bool

func (*DominatorTree) IsStrictDominatorOf

func (t *DominatorTree) IsStrictDominatorOf(dominator uint, dominated uint) bool

type Graph

type Graph struct {
	Nodes []Node
}

func NewEmptyGraph

func NewEmptyGraph(size uint) Graph

func NewGraph

func NewGraph(forwardEdges [][]uint) Graph

func NewGraphFromRootedTree

func NewGraphFromRootedTree(parents []uint) Graph

Converts a parent array that implicitly represents a rooted tree (by representing back edges only), into a full explicit graph representation, with explicit front edges.

Assumes that the root is identified by the only node v for which parent[v] = v.

func (*Graph) AddEdge

func (g *Graph) AddEdge(from, to uint)

func (*Graph) ControlFlowGraph

func (g *Graph) ControlFlowGraph(entry uint) ControlFlowGraph

func (*Graph) Dfs

func (g *Graph) Dfs(root uint) Dfs

Returns the 'Dfs' type that contains information about the graph that have been collected in a linear-time depth-first traversal of the graph from the provided node as the initial location.

func (*Graph) DominatorJoinGraph

func (g *Graph) DominatorJoinGraph(entry uint) DominatorJoinGraph

func (*Graph) DominatorTree

func (g *Graph) DominatorTree(entry uint) DominatorTree

Returns the 'DominatorTree' type that encapsulates the Dominator Tree data structure, and provides efficient queries of the dominators and immediate dominators of nodes.

Construction of the data structure is based on the Lengauer-Tarjan algorithm: https://doi.org/10.1145/357062.357071

func (*Graph) Equal

func (g *Graph) Equal(gt *Graph) bool

func (*Graph) LivenessAnalysis

func (g *Graph) LivenessAnalysis(use []set.Set[uint], def []set.Set[uint]) Liveness

func (*Graph) Size

func (g *Graph) Size() uint

Returns the number of nodes in the graph.

type LinkEvalForest

type LinkEvalForest struct {
	// SemiDom[v] is the semidominator of node v in the forest.
	// It is to be set by the user of the data structure.
	// Initially, SemiDom[v] = v for all v.
	SemiDom []uint

	// Parent[v] is the direct parent of node v in the forest.
	// If v is the root of the tree it is in, Parent[v] == v.
	// The data structure is initialized with Parent[v] = v for all v.
	Parent []uint
}

Nodes are assumed to be numbered [0, n), where n is the number of nodes.

func NewLinkEvalForest

func NewLinkEvalForest(n uint) LinkEvalForest

func (*LinkEvalForest) Eval

func (f *LinkEvalForest) Eval(v uint) uint

Eval(v) returns v if and only if it is the root in a tree of the forest. Otherwise, it returns a node u in the path from v to the root of the tree that contains v (not including the root itself), such that Semidominator(u) is minimal.

Since we are calculating the semidominators of vertices in reverse order, if evaluating a node that has yet to be processed and given a semidominator, the tree containing that node will be a singleton and thus it will be the root, and the node itself will be returned by definition.

If however, we evaluate a node that has already been processed, it must not be the root of the tree it is in, since right after processing a node we merge it with its parent. Then, the second case in the Eval definition applies, and we iterate over the ancestors of the node in the tree until reaching the root, returning the node with the minimal semidominator. On the way, we compress the path to the root of the tree, to speed up future evaluations.

For reference, see Henrik Knakkegaard Christensen's master's thesis, section 3.3, page 27: https://users-cs.au.dk/gerth/advising/thesis/henrik-knakkegaard-christensen.pdf

func (b *LinkEvalForest) Link(child uint, parent uint)

type Liveness

type Liveness struct {
	*Graph

	// LiveIn[v] contains the set of variables that are live at the entry of
	// the basic block represented by node v.
	LiveIn []set.Set[uint]

	// LiveOut[v] contains the set of variables that are live at the exit of
	// the basic block represented by node v.
	LiveOut []set.Set[uint]
}

type Node

type Node struct {
	ForwardEdges  []uint
	BackwardEdges []uint
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL