compiler/mir/analysis

  Source   Edit

This module implements various data-flow related analysis for MIR code. They're based on the mirexec traversal algorithms and a DataFlowGraph object corresponding to the code fragment (i.e., MirTree) that is analysed.

All analysis implemented here establish the relationship between two lvalues purely by inspecting their paths. For example, a.b and a.b are treated as equals, whereas a.b/c.d and a.b and x[].b are not. This means that run-time aliasing (e.g., through pointers) is not considered.

When a "before" or "after" relationship is mentioned in the context of operations, it doesn't refer to the relative memory location of the nodes representing the operations, but rather to the operations' control-flow relationship. If control-flow visits A first and then B, A is said to come before B and B to come after A. Not all operations are connected to each other through control-flow however, in which case the aforementioned relationship doesn't exist.

Procs

proc doesGlobalEscape(tree: MirTree; scope: Subgraph; start: InstrPos;
                      s: GlobalId): bool {....raises: [], tags: [].}
Computes if the global s potentially "escapes". A global escapes if it is not declared at module scope and is used inside a procedure that is then called outside the analysed global's scope. Example:
# a.nim
var p: proc()
block:
  var x = Resource(...)
  proc prc() =
    echo x
  
  p = prc # `x` "escapes" here
  # uncommenting the below would make `x` not escape
  # p = nil

p()
  Source   Edit
func isAlive(tree: MirTree; cfg: DataFlowGraph; span: Subgraph; loc: Path;
             start: InstrPos): bool {....raises: [], tags: [].}
Computes whether the location named by loc does contain a value (i.e., is alive) when the data-flow operation at start is reached (but not executed). Only the span sub-graph is considered by the analysis.   Source   Edit
func isLastRead(tree: MirTree; cfg: DataFlowGraph; span: Subgraph; loc: Path;
                start: InstrPos): bool {....raises: [], tags: [].}
Performs data-flow analysis to compute whether the value that loc evaluates to when start is reached (but not executed) is not observed by operations that have a control-flow dependency on the operation/statement at start and are located inside span. It's important to note that this analysis does not test whether the underlying location is accessed, but rather the value it stores. If a new value is assigned to the underlying location which is then accessed after, it won't cause the analysis to return false   Source   Edit
func isLastWrite(tree: MirTree; cfg: DataFlowGraph; span: Subgraph; loc: Path;
                 start: InstrPos): bool {....raises: [], tags: [].}
Computes whether the location loc is reassigned or modified on any paths starting from and including start, returning 'false' if yes and 'true' if not. In other words, computes whether a reassignment or mutation that has a control-flow dependency on start and is located inside span observes the current value.   Source   Edit
func skipConversions(tree: MirTree; val: OpValue): OpValue {....raises: [],
    tags: [].}
Returns the expression after skipping handle-only conversions.   Source   Edit