1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
//! Static Single Assignment (SSA) form for CIL methods.
//!
//! This module provides SSA transformation for .NET CIL bytecode, converting
//! stack-based operations into an explicit variable form where each variable
//! is assigned exactly once. This representation enables powerful optimizations
//! and analyses like constant propagation, dead code elimination, and type inference.
//!
//! # Architecture
//!
//! The SSA primitives ([`SsaVarId`], [`PhiNode`], [`SsaBlock`],
//! [`SsaFunction`], [`SsaOp`]) and analyses ([`SsaCfg`], [`PhiAnalyzer`],
//! [`SsaEvaluator`], …) live in `analyssa::ir` / `analyssa::analysis`. The
//! files in this directory are CIL-side boundary code:
//!
//! - [`builder`] - SSA construction driver (Cytron et al.) for CIL
//! - [`converter`] - CIL → SSA conversion
//! - [`decompose`] - CIL instruction decomposition into SSA ops
//! - [`stack`] - CIL stack-typing simulator
//! - [`types`] - CIL type system (`SsaType`, `TypeRef`, `MethodRef`, …)
//! - [`target`] - `CilTarget` impl of `analyssa::Target`
//! - [`exception`] - CIL exception handler bridge
//! - [`value`], [`ops`] - CIL extension impls on `analyssa::ConstValue` / `analyssa::SsaOp`
//! - [`function`] - CIL-pinned `SsaFunctionCilExt`/`Semantics` extensions
//! - [`resolver`] - CIL-side value resolver for inline values
//!
//! # CIL to SSA Transformation
//!
//! CIL is a stack-based instruction set, while SSA uses explicit variables.
//! The transformation involves several phases:
//!
//! 1. **Stack Simulation**: Convert implicit stack operations to explicit variables
//! 2. **Phi Placement**: Insert phi nodes at dominance frontiers
//! 3. **Variable Renaming**: Assign unique versions using dominator tree traversal
//!
//! ## Variable Origins
//!
//! SSA variables can originate from several sources:
//!
//! - **Arguments**: Method parameters (`ldarg`, `starg`)
//! - **Locals**: Local variables (`ldloc`, `stloc`)
//! - **Stack slots**: Temporary values from stack operations
//! - **Phi nodes**: Merged values at control flow joins
//!
//! ## Address-Taking Considerations
//!
//! Variables whose address is taken (`ldarga`, `ldloca`) require special handling
//! as they may be modified through pointers. These are tracked separately and
//! may be excluded from full SSA optimization.
//!
//! # Usage
//!
//! ```rust,ignore
//! use dotscope::analysis::{ControlFlowGraph, SsaConverter};
//! use dotscope::assembly::decode_blocks;
//!
//! // Build CFG from decoded blocks
//! let blocks = decode_blocks(data, offset, rva, Some(size))?;
//! let cfg = ControlFlowGraph::from_basic_blocks(blocks)?;
//!
//! // Construct SSA form
//! let ssa = SsaConverter::build(&cfg, num_args, num_locals, resolver)?;
//!
//! // Analyze phi nodes at merge points
//! for block in ssa.blocks() {
//! for phi in block.phi_nodes() {
//! println!("Phi: {:?} = phi({:?})", phi.result(), phi.operands());
//! }
//! }
//! ```
//!
//! # References
//!
//! - Cytron et al., "Efficiently Computing Static Single Assignment Form and the
//! Control Dependence Graph", ACM TOPLAS 1991
//! - Cooper & Torczon, "Engineering a Compiler", Chapter 9
// CIL-bound boundary code stays in dotscope (CIL → SSA conversion, stack
// typing, codegen extensions on analyssa types).
// Generic SSA primitives + analyses live in analyssa. The thin re-export
// shims that used to mediate via `mod cfg/consts/phi/...` collapsed into
// the `pub use` block below.
pub use SsaFunctionBuilder;
pub use SsaConverter;
pub use ;
pub use ;
pub use ;
// `SsaFunction`/`ReturnInfo`/`MethodPurity` live in `analyssa::ir::function`.
pub use MethodPurity;
/// CIL-defaulted alias of [`analyssa::ir::function::SsaFunction`].
pub type SsaFunction<T = CilTarget> = SsaFunction;
/// CIL-defaulted alias of [`analyssa::ir::function::ReturnInfo`].
pub type ReturnInfo<T = CilTarget> = ReturnInfo;
pub use ValueResolver;
pub use ;
pub use Z3Solver;
pub use ;
pub use CilTarget;
pub use ;
pub use ;
// Direct re-exports from analyssa for the now-collapsed shim files. Each line
// here used to be a one-line module file in `dotscope/src/analysis/ssa/`.
pub use ;
pub use ;
pub use Target;
pub use evaluate_const_op;
pub use ControlFlow;
pub use ;
/// CIL-defaulted alias of [`analyssa::ir::block::SsaBlock`].
pub type SsaBlock<T = CilTarget> = SsaBlock;
/// CIL-defaulted alias of [`analyssa::ir::instruction::SsaInstruction`].
pub type SsaInstruction<T = CilTarget> = SsaInstruction;
/// CIL-defaulted alias of [`analyssa::ir::variable::SsaVariable`].
pub type SsaVariable<T = CilTarget> = SsaVariable;
/// CIL-defaulted alias of [`analyssa::analysis::SsaCfg`].
pub type SsaCfg<'a, T = CilTarget> = SsaCfg;
/// CIL-defaulted alias of [`analyssa::analysis::consts::ConstEvaluator`].
pub type ConstEvaluator<'a, T = CilTarget> = ConstEvaluator;
/// CIL-defaulted alias of [`analyssa::analysis::evaluator::SsaEvaluator`].
pub type SsaEvaluator<'a, T = CilTarget> = SsaEvaluator;
/// CIL-defaulted alias of [`analyssa::analysis::evaluator::ExecutionTrace`].
pub type ExecutionTrace<T = CilTarget> = ExecutionTrace;
/// CIL-defaulted alias of [`analyssa::analysis::patterns::PatternDetector`].
pub type PatternDetector<'a, T = CilTarget> = PatternDetector;
/// CIL-defaulted alias of [`analyssa::analysis::patterns::DispatcherPattern`].
pub type DispatcherPattern<T = CilTarget> = DispatcherPattern;
/// CIL-defaulted alias of [`analyssa::analysis::patterns::SourceBlock`].
pub type SourceBlock<T = CilTarget> = SourceBlock;
/// CIL-defaulted alias of [`analyssa::analysis::patterns::OpaquePredicatePattern`].
pub type OpaquePredicatePattern<T = CilTarget> =
OpaquePredicatePattern;
/// CIL-defaulted alias of [`analyssa::analysis::patterns::PredicateResolution`].
pub type PredicateResolution<T = CilTarget> = PredicateResolution;
/// CIL-defaulted alias of [`analyssa::analysis::constraints::Constraint`].
pub type Constraint<T = CilTarget> = Constraint;
/// CIL-defaulted alias of [`analyssa::analysis::constraints::PathConstraint`].
pub type PathConstraint<T = CilTarget> = PathConstraint;
/// CIL-defaulted alias of [`analyssa::analysis::memory::MemoryLocation`].
pub type MemoryLocation<T = CilTarget> = MemoryLocation;
/// CIL-defaulted alias of [`analyssa::analysis::memory::MemoryOp`].
pub type MemoryOp<T = CilTarget> = MemoryOp;
/// CIL-defaulted alias of [`analyssa::analysis::memory::MemoryPhi`].
pub type MemoryPhi<T = CilTarget> = MemoryPhi;
/// CIL-defaulted alias of [`analyssa::analysis::memory::MemoryVersion`].
pub type MemoryVersion<T = CilTarget> = MemoryVersion;
/// CIL-defaulted alias of [`analyssa::analysis::verifier::SsaVerifier`].
pub type SsaVerifier<'a, T = CilTarget> = SsaVerifier;
/// Liveness analysis lifted to analyssa. Shim kept for back-compat.