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
//! Name mangling (Task 21, CG-055/CG-056/CG-057/CG-058/CG-059/CG-061): a
//! stable, dedup-aware internal symbol scheme, kept as a strictly separate
//! code path from DPI-visible naming (CG-059's "codegen owns the DPI C ABI
//! *and* the internal name-mangling scheme -- two distinct paths"
//! requirement; see `mangling_and_dpi_naming_are_two_distinct_code_paths`,
//! `tests/mangle.rs`, which greps `dpi.rs` for any call into this module and
//! vice versa).
//!
//! Internal (never DPI-visible) symbols follow
//! `_SV$<definition-name>$<param-binding-hash>$<entity-tag>$<local-name>`
//! (CG-056, `docs/design/codegen.md` ยง6): human-readable-prefixed for
//! debugger friendliness, hash-suffixed so dedup ("two structurally
//! identical instantiations of a parameterized module share one compiled
//! kernel, called from two call sites") never collides two *different*
//! param bindings of the same definition/tag/local (CG-058). DPI-visible
//! symbols are the opposite: never mangled by this crate at all --
//! [`dpi_linkage_name`] returns [`DpiExport::c_identifier`] verbatim
//! (CG-057), already fully resolved by slang itself (explicit
//! `export "DPI-C" alias = ...` vs. the default bare-name form).
//!
//! Cross-module calls (CG-061) resolve through this shared naming scheme,
//! not through any LLVM module-merge step: a worker lowering one
//! `InstanceBody`'s `Module` that calls a kernel defined in another
//! `InstanceBody`'s `Module` only ever needs `mangle_kernel` to reproduce
//! the callee's name and declares it `extern` (no body) in its own Module --
//! see `cross_module_call_resolves_via_mangled_extern_declaration`,
//! `tests/mangle.rs`, for the concrete two-`Module` proof.
use DefaultHasher;
use ;
use ;
/// The kind of internally-mangled entity a mangled symbol names (CG-056's
/// `<entity-tag>` template component). The derived [`std::fmt::Debug`]
/// output (`"Kernel"`, `"Process"`, `"DpiThunk"`, `"Helper"`) IS the tag's
/// literal textual form inside the mangled string -- see [`mangle_kernel`].
/// CG-056/CG-058: the public internal-symbol mangling function. Produces
/// `_SV$<def>$<param_hash>$<tag>$<local>` exactly -- `param_hash` rendered
/// as lower-case hex (compact, and visually distinct from `def`/`local`'s
/// own alphanumeric text, so a mangled name is never ambiguous about which
/// `$`-delimited field is the hash), `tag` via its `Debug` textual form. A
/// pure function of its four arguments -- no design/compilation state is
/// read, so two calls with identical arguments always produce identical
/// strings, and (CG-058) two calls that differ only in `param_hash` always
/// produce two distinct strings (the hash's hex digits appear verbatim in
/// the output, never elided/truncated).
/// CG-057: DPI-visible symbols are never mangled by this crate -- returns
/// `export.c_identifier()` verbatim (slang's own resolution of an explicit
/// `export "DPI-C" alias = ...` vs. the default bare subroutine name). A
/// deliberately trivial one-line wrapper, kept as its own named function
/// (never inlined at each call site) so `mangling_and_dpi_naming_are_two_
/// distinct_code_paths` has a single stable name to assert `mangle_kernel`
/// never appears in its call graph, and vice versa.
/// CG-055/CG-065: `DedupCache`'s key half (Task 23 reuses this unchanged
/// as-is) -- a canonical hash of every one of `sym`'s elaborated
/// `parameters()`' folded [`Symbol::constant_value`], in declaration order.
/// `Symbol::parameters()` itself already yields an empty iterator for any
/// symbol that is not an `Instance` (documented on that method: "count is 0
/// for non-instances"), so calling this on, say, a bare function symbol
/// deterministically hashes as "zero parameters" rather than erroring --
/// this is a pure hash-key helper with no lowering side effects, so it has
/// no `Result` to fail through. Two instances with structurally identical
/// (name, folded-value) parameter sequences always hash identically
/// (`two_instances_same_params_produce_one_symbol_two_call_sites`,
/// `tests/mangle.rs`), regardless of hierarchical instance path.
/// Canonicalizes one (optional) folded parameter value into `hasher`. Every
/// [`ConstantValue`] variant is hashed behind its own discriminant tag byte
/// first (so, e.g., an empty `String("")` can never collide with `Null`,
/// and an absent/unfolded `None` value -- its own tag `0` -- never
/// silently conflates with `Some(ConstantValue::Bad)`'s tag `9`).
/// `ConstantValue` is `#[non_exhaustive]` upstream, so the trailing wildcard
/// arm is structurally required here (unlike this crate's own exhaustive
/// `sv_lang::kinds` AST-kind matches, e.g. `expr.rs`/`func.rs`'s
/// `ExpressionKind`/`StatementKind` dispatch, which must never carry one): a
/// future slang-added variant still hashes deterministically under its own
/// reserved tag, it just cannot yet distinguish two different values of
/// that new variant from one another until this function is extended.