@scriptc/compiler 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (252) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +5 -2
  2. package/dist/backend/llvm/bigint-wrap.d.ts +4 -0
  3. package/dist/backend/llvm/bigint-wrap.js +590 -0
  4. package/dist/backend/llvm/bigint-wrap.js.map +1 -0
  5. package/dist/backend/llvm/blocks.d.ts +2 -0
  6. package/dist/backend/llvm/blocks.js +4 -0
  7. package/dist/backend/llvm/blocks.js.map +1 -1
  8. package/dist/backend/llvm/call-lifetimes.js +15 -4
  9. package/dist/backend/llvm/call-lifetimes.js.map +1 -1
  10. package/dist/backend/llvm/call-lifetimes.test.js +14 -3
  11. package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
  12. package/dist/backend/llvm/checked-narrows.test.js +1 -1
  13. package/dist/backend/llvm/checked-narrows.test.js.map +1 -1
  14. package/dist/backend/llvm/classes.js +57 -12
  15. package/dist/backend/llvm/classes.js.map +1 -1
  16. package/dist/backend/llvm/classes.test.js +4 -4
  17. package/dist/backend/llvm/classes.test.js.map +1 -1
  18. package/dist/backend/llvm/common.d.ts +7 -5
  19. package/dist/backend/llvm/common.js +7 -5
  20. package/dist/backend/llvm/common.js.map +1 -1
  21. package/dist/backend/llvm/constant-callbacks.js +10 -28
  22. package/dist/backend/llvm/constant-callbacks.js.map +1 -1
  23. package/dist/backend/llvm/dense-array-access.js +133 -45
  24. package/dist/backend/llvm/dense-array-access.js.map +1 -1
  25. package/dist/backend/llvm/dense-array-access.test.js +53 -1
  26. package/dist/backend/llvm/dense-array-access.test.js.map +1 -1
  27. package/dist/backend/llvm/dyn.d.ts +2 -0
  28. package/dist/backend/llvm/dyn.js +4 -0
  29. package/dist/backend/llvm/dyn.js.map +1 -1
  30. package/dist/backend/llvm/emitter.d.ts +120 -6
  31. package/dist/backend/llvm/emitter.js +676 -77
  32. package/dist/backend/llvm/emitter.js.map +1 -1
  33. package/dist/backend/llvm/emitter.test.js +14 -7
  34. package/dist/backend/llvm/emitter.test.js.map +1 -1
  35. package/dist/backend/llvm/expr-async.js +120 -43
  36. package/dist/backend/llvm/expr-async.js.map +1 -1
  37. package/dist/backend/llvm/expr-async.test.js +1 -1
  38. package/dist/backend/llvm/expr-async.test.js.map +1 -1
  39. package/dist/backend/llvm/expr-bytes.js +51 -36
  40. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  41. package/dist/backend/llvm/expr-callbacks.js +72 -3
  42. package/dist/backend/llvm/expr-callbacks.js.map +1 -1
  43. package/dist/backend/llvm/expr-calls.d.ts +1 -1
  44. package/dist/backend/llvm/expr-calls.js +159 -30
  45. package/dist/backend/llvm/expr-calls.js.map +1 -1
  46. package/dist/backend/llvm/expr-calls.test.d.ts +1 -0
  47. package/dist/backend/llvm/expr-calls.test.js +132 -0
  48. package/dist/backend/llvm/expr-calls.test.js.map +1 -0
  49. package/dist/backend/llvm/expr-containers.js +13 -0
  50. package/dist/backend/llvm/expr-containers.js.map +1 -1
  51. package/dist/backend/llvm/expr-context.d.ts +2 -0
  52. package/dist/backend/llvm/expr-dispatch.js +3 -0
  53. package/dist/backend/llvm/expr-dispatch.js.map +1 -1
  54. package/dist/backend/llvm/expr-dynamic.js +26 -4
  55. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  56. package/dist/backend/llvm/expr-primitives.d.ts +7 -0
  57. package/dist/backend/llvm/expr-primitives.js +80 -22
  58. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  59. package/dist/backend/llvm/expr-primitives.test.js +95 -5
  60. package/dist/backend/llvm/expr-primitives.test.js.map +1 -1
  61. package/dist/backend/llvm/expr-records.d.ts +9 -0
  62. package/dist/backend/llvm/expr-records.js +134 -16
  63. package/dist/backend/llvm/expr-records.js.map +1 -1
  64. package/dist/backend/llvm/expr-stream-bridges.d.ts +1 -1
  65. package/dist/backend/llvm/expr-stream-bridges.js +80 -1
  66. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  67. package/dist/backend/llvm/expr-stream-bridges.test.js +50 -1
  68. package/dist/backend/llvm/expr-stream-bridges.test.js.map +1 -1
  69. package/dist/backend/llvm/int32-abi.d.ts +31 -0
  70. package/dist/backend/llvm/int32-abi.js +62 -0
  71. package/dist/backend/llvm/int32-abi.js.map +1 -0
  72. package/dist/backend/llvm/int32-abi.test.d.ts +1 -0
  73. package/dist/backend/llvm/int32-abi.test.js +107 -0
  74. package/dist/backend/llvm/int32-abi.test.js.map +1 -0
  75. package/dist/backend/llvm/int32-locals.d.ts +30 -0
  76. package/dist/backend/llvm/int32-locals.js +95 -0
  77. package/dist/backend/llvm/int32-locals.js.map +1 -0
  78. package/dist/backend/llvm/integer-values.d.ts +4 -0
  79. package/dist/backend/llvm/integer-values.js +30 -1
  80. package/dist/backend/llvm/integer-values.js.map +1 -1
  81. package/dist/backend/llvm/integer-views.d.ts +8 -1
  82. package/dist/backend/llvm/integer-views.js +47 -2
  83. package/dist/backend/llvm/integer-views.js.map +1 -1
  84. package/dist/backend/llvm/lazy-captures.d.ts +16 -0
  85. package/dist/backend/llvm/lazy-captures.js +88 -2
  86. package/dist/backend/llvm/lazy-captures.js.map +1 -1
  87. package/dist/backend/llvm/lazy-captures.test.js +48 -0
  88. package/dist/backend/llvm/lazy-captures.test.js.map +1 -1
  89. package/dist/backend/llvm/lib-dispatch.js +14 -0
  90. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  91. package/dist/backend/llvm/lib-filesystem.js +3 -0
  92. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  93. package/dist/backend/llvm/lib-shared.js +7 -0
  94. package/dist/backend/llvm/lib-shared.js.map +1 -1
  95. package/dist/backend/llvm/local-array-reads.js +21 -2
  96. package/dist/backend/llvm/local-array-reads.js.map +1 -1
  97. package/dist/backend/llvm/local-array-reads.test.js +3 -2
  98. package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
  99. package/dist/backend/llvm/local-union-storage.test.js +2 -2
  100. package/dist/backend/llvm/local-union-storage.test.js.map +1 -1
  101. package/dist/backend/llvm/map-read-lifetimes.test.js +2 -2
  102. package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -1
  103. package/dist/backend/llvm/reference-effects.js +2 -0
  104. package/dist/backend/llvm/reference-effects.js.map +1 -1
  105. package/dist/backend/llvm/reference-writes.d.ts +3 -0
  106. package/dist/backend/llvm/reference-writes.js +10 -2
  107. package/dist/backend/llvm/reference-writes.js.map +1 -1
  108. package/dist/backend/llvm/regex-matchers.d.ts +39 -0
  109. package/dist/backend/llvm/regex-matchers.js +1649 -0
  110. package/dist/backend/llvm/regex-matchers.js.map +1 -0
  111. package/dist/backend/llvm/regex-matchers.test.d.ts +1 -0
  112. package/dist/backend/llvm/regex-matchers.test.js +96 -0
  113. package/dist/backend/llvm/regex-matchers.test.js.map +1 -0
  114. package/dist/backend/llvm/shapes.d.ts +36 -1
  115. package/dist/backend/llvm/shapes.js +127 -14
  116. package/dist/backend/llvm/shapes.js.map +1 -1
  117. package/dist/backend/llvm/stack-unions.test.js +1 -1
  118. package/dist/backend/llvm/stack-unions.test.js.map +1 -1
  119. package/dist/backend/llvm/string-construction.test.js +2 -2
  120. package/dist/backend/llvm/string-construction.test.js.map +1 -1
  121. package/dist/backend/llvm/string-lifetimes.test.js +5 -5
  122. package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
  123. package/dist/backend/llvm/string-literal-equality.d.ts +22 -0
  124. package/dist/backend/llvm/string-literal-equality.js +78 -0
  125. package/dist/backend/llvm/string-literal-equality.js.map +1 -0
  126. package/dist/backend/llvm/switch-dispatch.js +59 -13
  127. package/dist/backend/llvm/switch-dispatch.js.map +1 -1
  128. package/dist/backend/llvm/switch-dispatch.test.js +71 -6
  129. package/dist/backend/llvm/switch-dispatch.test.js.map +1 -1
  130. package/dist/backend/llvm/union-retype.test.d.ts +1 -0
  131. package/dist/backend/llvm/union-retype.test.js +229 -0
  132. package/dist/backend/llvm/union-retype.test.js.map +1 -0
  133. package/dist/backend/llvm/wrapping-sums.d.ts +17 -0
  134. package/dist/backend/llvm/wrapping-sums.js +113 -0
  135. package/dist/backend/llvm/wrapping-sums.js.map +1 -0
  136. package/dist/backend/loop-polls.js +1 -0
  137. package/dist/backend/loop-polls.js.map +1 -1
  138. package/dist/backend/mangle.d.ts +9 -0
  139. package/dist/backend/mangle.js +15 -0
  140. package/dist/backend/mangle.js.map +1 -1
  141. package/dist/backend/may-throw.js +6 -3
  142. package/dist/backend/may-throw.js.map +1 -1
  143. package/dist/backend/runtime-abi.d.ts +2 -2
  144. package/dist/backend/runtime-abi.js +2 -2
  145. package/dist/backend/runtime-pack-targets.test.js +1 -1
  146. package/dist/backend/runtime-pack.test.js +1 -1
  147. package/dist/contracts/check.js +4 -0
  148. package/dist/contracts/check.js.map +1 -1
  149. package/dist/frontend/lowering/array-values.d.ts +14 -0
  150. package/dist/frontend/lowering/array-values.js +29 -0
  151. package/dist/frontend/lowering/array-values.js.map +1 -1
  152. package/dist/frontend/lowering/containers/array-callbacks.js +40 -0
  153. package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
  154. package/dist/frontend/lowering/containers/array-pipelines.d.ts +54 -0
  155. package/dist/frontend/lowering/containers/array-pipelines.js +1827 -0
  156. package/dist/frontend/lowering/containers/array-pipelines.js.map +1 -0
  157. package/dist/frontend/lowering/containers/exec-result-uses.d.ts +10 -0
  158. package/dist/frontend/lowering/containers/exec-result-uses.js +88 -0
  159. package/dist/frontend/lowering/containers/exec-result-uses.js.map +1 -0
  160. package/dist/frontend/lowering/containers/string-and-regexp.js +15 -7
  161. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  162. package/dist/frontend/lowering/containers/string-replacement.d.ts +2 -1
  163. package/dist/frontend/lowering/containers/string-replacement.js +32 -136
  164. package/dist/frontend/lowering/containers/string-replacement.js.map +1 -1
  165. package/dist/frontend/lowering/devirtualize.d.ts +33 -0
  166. package/dist/frontend/lowering/devirtualize.js +199 -0
  167. package/dist/frontend/lowering/devirtualize.js.map +1 -0
  168. package/dist/frontend/lowering/expressions/nullish-assignment.js +55 -7
  169. package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
  170. package/dist/frontend/lowering/identifier-uses.d.ts +7 -0
  171. package/dist/frontend/lowering/identifier-uses.js +23 -0
  172. package/dist/frontend/lowering/identifier-uses.js.map +1 -0
  173. package/dist/frontend/lowering/iterator-adapters.js +51 -3
  174. package/dist/frontend/lowering/iterator-adapters.js.map +1 -1
  175. package/dist/frontend/lowering/lower-array-sort.js +13 -0
  176. package/dist/frontend/lowering/lower-array-sort.js.map +1 -1
  177. package/dist/frontend/lowering/lower-calls.js +64 -30
  178. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  179. package/dist/frontend/lowering/lower-classes.js +1 -11
  180. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  181. package/dist/frontend/lowering/lower-console.d.ts +14 -0
  182. package/dist/frontend/lowering/lower-console.js +195 -0
  183. package/dist/frontend/lowering/lower-console.js.map +1 -0
  184. package/dist/frontend/lowering/lower-exprs.js +135 -3
  185. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  186. package/dist/frontend/lowering/lower-functions.js +7 -3
  187. package/dist/frontend/lowering/lower-functions.js.map +1 -1
  188. package/dist/frontend/lowering/lower-generators.d.ts +10 -0
  189. package/dist/frontend/lowering/lower-generators.js +108 -41
  190. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  191. package/dist/frontend/lowering/lower-modules.js +4 -0
  192. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  193. package/dist/frontend/lowering/lower-stream.js +13 -10
  194. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  195. package/dist/frontend/lowering/lowerer.d.ts +25 -4
  196. package/dist/frontend/lowering/lowerer.js +120 -47
  197. package/dist/frontend/lowering/lowerer.js.map +1 -1
  198. package/dist/frontend/lowering/nan-coded-reads.d.ts +16 -0
  199. package/dist/frontend/lowering/nan-coded-reads.js +108 -1
  200. package/dist/frontend/lowering/nan-coded-reads.js.map +1 -1
  201. package/dist/frontend/lowering/runtime-optional-bounds.d.ts +4 -0
  202. package/dist/frontend/lowering/runtime-optional-bounds.js +2 -0
  203. package/dist/frontend/lowering/runtime-optional-bounds.js.map +1 -1
  204. package/dist/frontend/lowering/runtime-optional-bounds.test.js +27 -0
  205. package/dist/frontend/lowering/runtime-optional-bounds.test.js.map +1 -1
  206. package/dist/frontend/lowering/split-consumers.js +2 -18
  207. package/dist/frontend/lowering/split-consumers.js.map +1 -1
  208. package/dist/frontend/lowering/surfaces.js +3 -8
  209. package/dist/frontend/lowering/surfaces.js.map +1 -1
  210. package/dist/frontend/lowering/union-retag.d.ts +6 -1
  211. package/dist/frontend/lowering/union-retag.js +64 -1
  212. package/dist/frontend/lowering/union-retag.js.map +1 -1
  213. package/dist/frontend/lowering/union-retag.test.js +46 -0
  214. package/dist/frontend/lowering/union-retag.test.js.map +1 -1
  215. package/dist/frontend/type-mapper.js +16 -3
  216. package/dist/frontend/type-mapper.js.map +1 -1
  217. package/dist/ir/builtin-effects.js +2 -0
  218. package/dist/ir/builtin-effects.js.map +1 -1
  219. package/dist/ir/builtin-signatures.d.ts +1 -1
  220. package/dist/ir/builtin-signatures.js +12 -1
  221. package/dist/ir/builtin-signatures.js.map +1 -1
  222. package/dist/ir/function-references.d.ts +12 -0
  223. package/dist/ir/function-references.js +29 -0
  224. package/dist/ir/function-references.js.map +1 -0
  225. package/dist/ir/function-references.test.d.ts +1 -0
  226. package/dist/ir/function-references.test.js +276 -0
  227. package/dist/ir/function-references.test.js.map +1 -0
  228. package/dist/ir/int32-slots.d.ts +7 -4
  229. package/dist/ir/int32-slots.js +214 -49
  230. package/dist/ir/int32-slots.js.map +1 -1
  231. package/dist/ir/int32-slots.test.js +38 -1
  232. package/dist/ir/int32-slots.test.js.map +1 -1
  233. package/dist/ir/integer-ranges.d.ts +4 -4
  234. package/dist/ir/integer-ranges.js +89 -64
  235. package/dist/ir/integer-ranges.js.map +1 -1
  236. package/dist/ir/integer-ranges.test.js +71 -9
  237. package/dist/ir/integer-ranges.test.js.map +1 -1
  238. package/dist/ir/intrinsic-signatures.js +1 -0
  239. package/dist/ir/intrinsic-signatures.js.map +1 -1
  240. package/dist/ir/ir.d.ts +52 -6
  241. package/dist/ir/ir.js +1 -0
  242. package/dist/ir/ir.js.map +1 -1
  243. package/dist/ir/runtime-features.js +3 -2
  244. package/dist/ir/runtime-features.js.map +1 -1
  245. package/dist/ir/traverse.js +4 -0
  246. package/dist/ir/traverse.js.map +1 -1
  247. package/dist/ir/validate.js +57 -6
  248. package/dist/ir/validate.js.map +1 -1
  249. package/dist/ir/validate.test.js +25 -7
  250. package/dist/ir/validate.test.js.map +1 -1
  251. package/package.json +20 -20
  252. package/surface-manifest.json +1 -17
@@ -0,0 +1,62 @@
1
+ import { everyStmtList } from "../../ir/traverse.js";
2
+ /** Suffix of a function's i32 entry symbol. The ordinary symbol stays a
3
+ * double-ABI wrapper around it. */
4
+ export const INT32_ABI_SUFFIX = ".i32";
5
+ /** Functions whose direct calls pass int32 parameters and results in
6
+ * integer registers.
7
+ *
8
+ * A parameter qualifies when analyzeInt32Slots proved its incoming value
9
+ * an int32 at every call site (it only does so for functions reached by
10
+ * direct calls alone, never as values, through virtual dispatch or from
11
+ * the runtime) or an Int32 contract pins it. A result qualifies when every
12
+ * return is proven an int32. The proofs exclude -0, NaN and fractions, so
13
+ * the i32 converts back to the same double. A parameter that a number
14
+ * (not i32) result returns as is, like `n` in `n < 2 ? n : fib(n - 1) +
15
+ * fib(n - 2)`, keeps its double: the incoming double is that result, where
16
+ * an i32 would add a conversion to the path that returns it.
17
+ *
18
+ * Only direct `call` and `new` sites use the i32 entry. Every other way to
19
+ * reach the function (closure and virtual-dispatch entries, constructor
20
+ * thunks, adapters, the runtime) keeps the double-ABI symbol, which becomes
21
+ * a thin wrapper that converts and calls the i32 entry. Async functions and
22
+ * generators keep their own entries; library builds (no slot facts) and
23
+ * debug builds (numbers stay doubles for the debugger) select none. */
24
+ export function findInt32Abis(mod, slots) {
25
+ const result = new Map();
26
+ for (const fn of mod.functions) {
27
+ if (fn.async || fn.generator || fn.captures !== undefined || !slots.called.has(fn.name))
28
+ continue;
29
+ const ret = fn.returnType.kind === "f64" && slots.hasReturn(fn.name);
30
+ let params = fn.params.map((param) => param.type.kind === "f64" && slots.hasParam(fn.name, param.localId));
31
+ if (!ret && params.includes(true)) {
32
+ const returned = returnedLocals(fn);
33
+ params = params.map((i32, index) => i32 && !returned.has(fn.params[index].localId));
34
+ }
35
+ if (ret || params.includes(true))
36
+ result.set(fn.name, { params, result: ret });
37
+ }
38
+ return result;
39
+ }
40
+ /** Locals some `return` hands back as its value (directly or as an arm of
41
+ * a conditional). */
42
+ function returnedLocals(fn) {
43
+ const result = new Set();
44
+ const value = (e) => {
45
+ if (e.kind === "varRef")
46
+ result.add(e.localId);
47
+ else if (e.kind === "ternary") {
48
+ value(e.then);
49
+ value(e.else_);
50
+ }
51
+ };
52
+ everyStmtList(fn.body, {
53
+ stmt: (s) => {
54
+ if (s.kind === "return" && s.value)
55
+ value(s.value);
56
+ return true;
57
+ },
58
+ expr: () => true,
59
+ });
60
+ return result;
61
+ }
62
+ //# sourceMappingURL=int32-abi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"int32-abi.js","sourceRoot":"","sources":["../../../src/backend/llvm/int32-abi.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AASrD;mCACmC;AACnC,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEvC;;;;;;;;;;;;;;;;;;uEAkBuE;AACvE,MAAM,UAAU,aAAa,CAAC,GAAa,EAAE,KAAiB;IAC5D,MAAM,MAAM,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC3C,KAAK,MAAM,EAAE,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;QAC/B,IAAI,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC;YACrF,SAAS;QACX,MAAM,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,KAAK,KAAK,IAAI,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QACrE,IAAI,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CACxB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAC/E,CAAC;QACF,IAAI,CAAC,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAClC,MAAM,QAAQ,GAAG,cAAc,CAAC,EAAE,CAAC,CAAC;YACpC,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QACvF,CAAC;QACD,IAAI,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;qBACqB;AACrB,SAAS,cAAc,CAAC,EAAc;IACpC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IACjC,MAAM,KAAK,GAAG,CAAC,CAAS,EAAQ,EAAE;QAChC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;aAC1C,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACd,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC;IACH,CAAC,CAAC;IACF,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE;QACrB,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE;YACV,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK;gBAAE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACnD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI;KACjB,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,107 @@
1
+ import { expect, test } from "vitest";
2
+ import { BOOL, F64, STRING, VOID, funcOf, } from "../../ir/ir.js";
3
+ import { validateModule } from "../../ir/validate.js";
4
+ import { emitLlvmModule } from "./emitter.js";
5
+ const loc = { file: "int32-abi.ts", start: 0, end: 0 };
6
+ const num = (value) => ({ kind: "numLit", value, type: F64, loc });
7
+ const ref = (localId) => ({ kind: "varRef", localId, type: F64, loc });
8
+ const bin = (op, left, right) => ({
9
+ kind: "bin",
10
+ op,
11
+ left,
12
+ right,
13
+ type: F64,
14
+ loc,
15
+ });
16
+ const call = (callee, args, type = F64) => ({
17
+ kind: "call",
18
+ callee,
19
+ args,
20
+ type,
21
+ loc,
22
+ });
23
+ const stmt = (expr) => ({ kind: "exprStmt", expr, loc });
24
+ const ret = (value) => ({ kind: "return", value, loc });
25
+ function fn(name, params, body, returnType = F64) {
26
+ return {
27
+ name,
28
+ params: params.map((id) => ({ localId: id, name: id, type: F64 })),
29
+ locals: params.map((id) => ({ id, name: id, type: F64, mutable: true })),
30
+ returnType,
31
+ body,
32
+ loc,
33
+ };
34
+ }
35
+ function module() {
36
+ return {
37
+ irVersion: 16,
38
+ sourceFile: loc.file,
39
+ entry: "main",
40
+ functions: [
41
+ fn("main", [], [
42
+ stmt(call("mix", [num(3), num(4)])),
43
+ stmt(call("half", [num(6)])),
44
+ stmt(call("bits", [num(5)])),
45
+ stmt({ kind: "closure", fnName: "bits", captures: [], type: funcOf([F64], F64), loc }),
46
+ stmt(call("checked", [num(2)])),
47
+ stmt(call("leaf", [num(9)])),
48
+ ], VOID),
49
+ // int32 parameters and result.
50
+ fn("mix", ["h", "i"], [ret(bin("|", bin("^", ref("h"), ref("i")), num(0)))]),
51
+ // int32 parameter, number result.
52
+ fn("half", ["n"], [ret(bin("*", ref("n"), num(0.5)))]),
53
+ // Escapes as a value: its parameter is unknown, its result int32.
54
+ fn("bits", ["n"], [ret(bin("|", ref("n"), num(0)))]),
55
+ // Returns its parameter as a number result: the parameter stays double.
56
+ fn("leaf", ["n"], [
57
+ {
58
+ kind: "if",
59
+ cond: { kind: "bin", op: "<", left: ref("n"), right: num(2), type: BOOL, loc },
60
+ then: [ret(ref("n"))],
61
+ else_: [ret(bin("*", ref("n"), num(0.5)))],
62
+ loc,
63
+ },
64
+ ]),
65
+ // A throwing call inside an i32 body.
66
+ fn("checked", ["n"], [stmt(call("throws", [], VOID)), ret(bin("|", ref("n"), num(1)))]),
67
+ fn("throws", [], [{ kind: "throw", value: { kind: "strLit", value: "no", type: STRING, loc }, loc }], VOID),
68
+ ],
69
+ };
70
+ }
71
+ function define(llvm, symbol) {
72
+ const escaped = symbol.replace(/\./g, "\\.");
73
+ return new RegExp(`^define internal [^\\n]*@${escaped}\\([^]*?^}`, "m").exec(llvm)[0];
74
+ }
75
+ test("int32 parameters and results use an i32 entry on direct calls", () => {
76
+ const mod = module();
77
+ expect(validateModule(mod)).toEqual([]);
78
+ const llvm = emitLlvmModule(mod);
79
+ expect(llvm).toMatch(/define internal i32 @sc_f_mix\.i32\(i32 %p_\w+\.i32, i32 %p_\w+\.i32\)/);
80
+ expect(llvm).toMatch(/define internal double @sc_f_half\.i32\(i32 %p_\w+\.i32\)/);
81
+ expect(llvm).toMatch(/define internal i32 @sc_f_bits\.i32\(double %p_\w+\)/);
82
+ const main = define(llvm, "sc_f_main");
83
+ expect(main).toContain("call i32 @sc_f_mix.i32(i32 3, i32 4)");
84
+ expect(main).toContain("call double @sc_f_half.i32(i32 6)");
85
+ expect(main).toContain("call i32 @sc_f_bits.i32(double ");
86
+ expect(main).toContain("call double @sc_f_leaf(double ");
87
+ expect(llvm).not.toContain("@sc_f_leaf.i32");
88
+ // The closure keeps the double-ABI symbol, a wrapper around the i32 entry.
89
+ expect(llvm).not.toMatch(/ptr @sc_f_bits\.i32\b/);
90
+ const wrapper = define(llvm, "sc_f_mix");
91
+ expect(wrapper).toContain("define internal double @sc_f_mix(double %p0, double %p1)");
92
+ expect(wrapper).toContain("%a0 = fptosi double %p0 to i32");
93
+ expect(wrapper).toContain("%r = call i32 @sc_f_mix.i32(i32 %a0, i32 %a1)");
94
+ expect(wrapper).toContain("%d = sitofp i32 %r to double");
95
+ // The exceptional exit of an i32 body returns an i32.
96
+ const checked = define(llvm, "sc_f_checked.i32");
97
+ expect(checked).toContain("ret i32 0");
98
+ expect(checked).not.toContain("ret double");
99
+ });
100
+ test("debug builds keep the double ABI", () => {
101
+ const llvm = emitLlvmModule(module(), {
102
+ debugSources: new Map([[loc.file, "function main() {}"]]),
103
+ });
104
+ expect(llvm).not.toContain(".i32(");
105
+ expect(llvm).toMatch(/define internal double @sc_f_mix\(double %p_\w+, double %p_\w+\)/);
106
+ });
107
+ //# sourceMappingURL=int32-abi.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"int32-abi.test.js","sourceRoot":"","sources":["../../../src/backend/llvm/int32-abi.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { IrExpr, IrFunction } from "../../ir/ir.js";
2
+ import { type IntegerRange, type IntegerRanges, type IntegerSlotFacts } from "../../ir/integer-ranges.js";
3
+ /** How an int32-stored local holds its value: the i32 bits of an int32
4
+ * (`signed`) or of a uint32, and the range every write lands in. */
5
+ export interface Int32Local {
6
+ signed: boolean;
7
+ range: IntegerRange;
8
+ /** A parameter the body never writes: its incoming double is still
9
+ * its value, so reads use it instead of widening the i32 again. */
10
+ incoming?: boolean;
11
+ }
12
+ /** Number locals whose every write is an exact int32 (or every write an
13
+ * exact uint32), so an i32 slot can be their only storage. A read widens
14
+ * the i32 back to the same double, which is exact because the range
15
+ * analysis never proves -0, NaN or a fraction; integer consumers take the
16
+ * i32 directly, and no double is carried through loops.
17
+ *
18
+ * A write qualifies through its proven range (analyzeIntegerRanges), or,
19
+ * for an Int32 contract local, through the contract, which checked every
20
+ * write with the same analysis. `++`/`--` qualify through the range of the
21
+ * value they write. A parameter also needs a proof for its incoming value
22
+ * (every call site, or its contract). For-of and catch bindings, captured,
23
+ * boxed and TDZ locals keep their ordinary storage, as do async functions
24
+ * and generators, whose locals live in frames the range analysis does not
25
+ * follow (it proves nothing there). `excluded` names further locals the
26
+ * caller reads through other storage. */
27
+ export declare function findInt32Locals(fn: IrFunction, ranges: IntegerRanges, facts: IntegerSlotFacts, excluded: ReadonlySet<string>): {
28
+ locals: Map<string, Int32Local>;
29
+ values: ReadonlySet<IrExpr>;
30
+ };
@@ -0,0 +1,95 @@
1
+ import { integerArithmeticRange, withinInt32, withinUint32, } from "../../ir/integer-ranges.js";
2
+ import { everyExprChild, everyStmtChild } from "../../ir/traverse.js";
3
+ /** Number locals whose every write is an exact int32 (or every write an
4
+ * exact uint32), so an i32 slot can be their only storage. A read widens
5
+ * the i32 back to the same double, which is exact because the range
6
+ * analysis never proves -0, NaN or a fraction; integer consumers take the
7
+ * i32 directly, and no double is carried through loops.
8
+ *
9
+ * A write qualifies through its proven range (analyzeIntegerRanges), or,
10
+ * for an Int32 contract local, through the contract, which checked every
11
+ * write with the same analysis. `++`/`--` qualify through the range of the
12
+ * value they write. A parameter also needs a proof for its incoming value
13
+ * (every call site, or its contract). For-of and catch bindings, captured,
14
+ * boxed and TDZ locals keep their ordinary storage, as do async functions
15
+ * and generators, whose locals live in frames the range analysis does not
16
+ * follow (it proves nothing there). `excluded` names further locals the
17
+ * caller reads through other storage. */
18
+ export function findInt32Locals(fn, ranges, facts, excluded) {
19
+ const result = new Map();
20
+ // The written values the proof covers; the emitter stores no other.
21
+ const values = new Set();
22
+ if (fn.async || fn.generator || ranges.size === 0)
23
+ return { locals: result, values };
24
+ const captured = new Set([...(fn.captures ?? []), ...(fn.classCaptures ?? [])].map((c) => c.localId));
25
+ const contract = (id) => facts.locals?.(id) ?? null;
26
+ const writes = new Map();
27
+ for (const local of fn.locals) {
28
+ if (local.type.kind !== "f64" || local.boxed || local.tdz)
29
+ continue;
30
+ if (captured.has(local.id) || excluded.has(local.id))
31
+ continue;
32
+ writes.set(local.id, []);
33
+ }
34
+ const params = new Set();
35
+ for (const param of fn.params) {
36
+ const list = writes.get(param.localId);
37
+ if (!list)
38
+ continue;
39
+ list.push(facts.params?.get(param.localId) ?? contract(param.localId));
40
+ params.add(param.localId);
41
+ }
42
+ const write = (id, range, value) => {
43
+ const list = writes.get(id);
44
+ if (!list)
45
+ return;
46
+ list.push(range ?? contract(id));
47
+ if (value)
48
+ values.add(value);
49
+ };
50
+ const expr = (node) => {
51
+ if (node.kind === "assignExpr")
52
+ write(node.localId, ranges.get(node.value), node.value);
53
+ else if (node.kind === "incDec") {
54
+ // The analysis records the value the expression yields: the new
55
+ // value for prefix forms, the old one for postfix forms.
56
+ const yielded = ranges.get(node) ?? null;
57
+ write(node.localId, yielded && !node.prefix
58
+ ? integerArithmeticRange(node.op, yielded, { min: 1, max: 1 })
59
+ : yielded, node);
60
+ }
61
+ return everyExprChild(node, expr, stmt);
62
+ };
63
+ const stmt = (node) => {
64
+ if (node.kind === "varDecl") {
65
+ if (node.init)
66
+ write(node.localId, ranges.get(node.init), node.init);
67
+ }
68
+ else if (node.kind === "assign")
69
+ write(node.localId, ranges.get(node.value), node.value);
70
+ else if (node.kind === "forOf")
71
+ writes.get(node.localId)?.push(null);
72
+ else if (node.kind === "tryCatch" && node.catchLocalId)
73
+ writes.get(node.catchLocalId)?.push(null);
74
+ return everyStmtChild(node, expr, stmt);
75
+ };
76
+ fn.body.every(stmt);
77
+ for (const [id, list] of writes) {
78
+ // An unwritten local is never read as a number.
79
+ if (list.length === 0 || list.some((range) => range === null))
80
+ continue;
81
+ const range = { min: Infinity, max: -Infinity };
82
+ for (const write of list) {
83
+ range.min = Math.min(range.min, write.min);
84
+ range.max = Math.max(range.max, write.max);
85
+ }
86
+ if (!withinInt32(range) && !withinUint32(range))
87
+ continue;
88
+ const local = { signed: withinInt32(range), range };
89
+ if (params.has(id) && list.length === 1)
90
+ local.incoming = true;
91
+ result.set(id, local);
92
+ }
93
+ return { locals: result, values };
94
+ }
95
+ //# sourceMappingURL=int32-locals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"int32-locals.js","sourceRoot":"","sources":["../../../src/backend/llvm/int32-locals.ts"],"names":[],"mappings":"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"}
@@ -7,4 +7,8 @@ export type LlInteger = NonNullable<LlValue["integer"]>;
7
7
  * are reused only when the range proves they have not lost high bits. */
8
8
  export declare function exactInteger(host: LlvmEmitterContext, value: LlValue, expr?: IrExpr): LlInteger | null;
9
9
  export declare function widenInteger(host: LlvmEmitterContext, value: LlInteger): string;
10
+ /** The i32 of an integer whose range is within int32. */
11
+ export declare function narrowInteger(host: LlvmEmitterContext, value: LlInteger): string;
12
+ /** `integerNumber` for an i32 whose range is within int32. */
13
+ export declare function int32Number(host: LlvmEmitterContext, name: string, range: IntegerRange, type: IrType): LlValue;
10
14
  export declare function integerNumber(host: LlvmEmitterContext, name: string, range: IntegerRange, type: IrType): LlValue;
@@ -31,6 +31,12 @@ export function exactInteger(host, value, expr) {
31
31
  if (value.uint32 !== undefined && range.min >= -2147483648 && range.max <= 2147483647) {
32
32
  return { name: value.uint32, type: "i32", signed: true, range };
33
33
  }
34
+ if (range.min >= -2147483648 && range.max <= 2147483647) {
35
+ // An int32 conversion lets LLVM fold it with an int32 source's sitofp.
36
+ const name = host.B.tmp();
37
+ host.B.line(`${name} = fptosi double ${value.name} to i32`);
38
+ return { name, type: "i32", signed: true, range };
39
+ }
34
40
  const name = host.B.tmp();
35
41
  host.B.line(`${name} = fptosi double ${value.name} to i64`);
36
42
  return { name, type: "i64", signed: true, range };
@@ -42,11 +48,34 @@ export function widenInteger(host, value) {
42
48
  host.B.line(`${wide} = ${value.signed ? "sext" : "zext"} i32 ${value.name} to i64`);
43
49
  return wide;
44
50
  }
51
+ /** The i32 of an integer whose range is within int32. */
52
+ export function narrowInteger(host, value) {
53
+ if (value.type === "i32")
54
+ return value.name;
55
+ const narrow = host.B.tmp();
56
+ host.B.line(`${narrow} = trunc i64 ${value.name} to i32`);
57
+ return narrow;
58
+ }
59
+ /** `integerNumber` for an i32 whose range is within int32. */
60
+ export function int32Number(host, name, range, type) {
61
+ const number = host.B.tmp();
62
+ host.B.line(`${number} = sitofp i32 ${name} to double`);
63
+ return { name: number, type, uint32: name, integer: { name, type: "i32", signed: true, range } };
64
+ }
45
65
  export function integerNumber(host, name, range, type) {
46
66
  const number = host.B.tmp();
47
67
  const uint32 = host.B.tmp();
48
- host.B.line(`${number} = sitofp i64 ${name} to double`);
49
68
  host.B.line(`${uint32} = trunc i64 ${name} to i32`);
69
+ // A proven int32 converts from its low half. The value is the same, but
70
+ // LLVM folds `fptosi (sitofp i32 x)` back to x, also through the phis of
71
+ // loop-carried locals (whose other incoming values are int32 too, such as
72
+ // `x | 0`), while a 64-bit source is not known to convert exactly. So a
73
+ // counter written `i = (i + 1) | 0` stays an integer instead of taking a
74
+ // double round trip on every iteration.
75
+ const int32 = range.min >= -2147483648 && range.max <= 2147483647;
76
+ host.B.line(int32
77
+ ? `${number} = sitofp i32 ${uint32} to double`
78
+ : `${number} = sitofp i64 ${name} to double`);
50
79
  return { name: number, type, uint32, integer: { name, type: "i64", signed: true, range } };
51
80
  }
52
81
  //# sourceMappingURL=integer-values.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"integer-values.js","sourceRoot":"","sources":["../../../src/backend/llvm/integer-values.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"integer-values.js","sourceRoot":"","sources":["../../../src/backend/llvm/integer-values.ts"],"names":[],"mappings":"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"}
@@ -3,5 +3,12 @@ import type { IrFunction } from "../../ir/ir.js";
3
3
  * consumers in loops can reuse it. The number remains authoritative for floating
4
4
  * arithmetic, signed zero, returns and zero-iteration loops. Only explicit
5
5
  * local stores maintain these views; captures and implicit binders stay on
6
- * the ordinary path. No range or integer assumption is made about inputs. */
6
+ * the ordinary path. No range or integer assumption is made about inputs.
7
+ *
8
+ * A declared local that only ever holds bitwise results (`c = units[i] | 0`)
9
+ * also gets a view when a loop compares it: its stores already have the
10
+ * integer, and compares of the view stay integer compares. Without it each
11
+ * compare converts the stored number back, and LLVM moves that number's
12
+ * conversion into the join of a NaN-coded typed-array read (`phi [sitofp x,
13
+ * 0.0]`), where nothing folds it back to the integer. */
7
14
  export declare function findIntegerViews(fn: IrFunction): Set<string>;
@@ -4,7 +4,14 @@ import { byteNumberAccess } from "../../ir/byte-numbers.js";
4
4
  * consumers in loops can reuse it. The number remains authoritative for floating
5
5
  * arithmetic, signed zero, returns and zero-iteration loops. Only explicit
6
6
  * local stores maintain these views; captures and implicit binders stay on
7
- * the ordinary path. No range or integer assumption is made about inputs. */
7
+ * the ordinary path. No range or integer assumption is made about inputs.
8
+ *
9
+ * A declared local that only ever holds bitwise results (`c = units[i] | 0`)
10
+ * also gets a view when a loop compares it: its stores already have the
11
+ * integer, and compares of the view stay integer compares. Without it each
12
+ * compare converts the stored number back, and LLVM moves that number's
13
+ * conversion into the join of a NaN-coded typed-array read (`phi [sitofp x,
14
+ * 0.0]`), where nothing folds it back to the integer. */
8
15
  export function findIntegerViews(fn) {
9
16
  const wanted = new Set();
10
17
  if (fn.async || fn.generator)
@@ -16,7 +23,23 @@ export function findIntegerViews(fn) {
16
23
  if (loopDepth > 0 && expr.kind === "varRef" && expr.type.kind === "f64")
17
24
  wanted.add(expr.localId);
18
25
  };
26
+ const declared = new Set();
27
+ const compared = new Set();
28
+ const nonBitwise = new Set(fn.params.map((p) => p.localId));
29
+ const stored = (localId, value) => {
30
+ if (!value || !bitwiseValue(value))
31
+ nonBitwise.add(localId);
32
+ };
19
33
  const expr = (node) => {
34
+ if (node.kind === "assignExpr")
35
+ stored(node.localId, node.value);
36
+ else if (node.kind === "incDec")
37
+ nonBitwise.add(node.localId);
38
+ else if (loopDepth > 0 && node.kind === "bin" && COMPARES.has(node.op)) {
39
+ for (const side of [node.left, node.right])
40
+ if (side.kind === "varRef" && side.type.kind === "f64")
41
+ compared.add(side.localId);
42
+ }
20
43
  if (node.kind === "bin" &&
21
44
  (node.op === "&" ||
22
45
  node.op === "|" ||
@@ -47,8 +70,13 @@ export function findIntegerViews(fn) {
47
70
  node.kind === "doWhile";
48
71
  if (loop)
49
72
  loopDepth++;
50
- if (node.kind === "varDecl")
73
+ if (node.kind === "varDecl") {
51
74
  initialized.add(node.localId);
75
+ declared.add(node.localId);
76
+ stored(node.localId, node.init);
77
+ }
78
+ else if (node.kind === "assign")
79
+ stored(node.localId, node.value);
52
80
  if (node.kind === "forOf")
53
81
  excluded.add(node.localId);
54
82
  // Canonical induction is maintained separately by the loop emitter.
@@ -68,6 +96,9 @@ export function findIntegerViews(fn) {
68
96
  // A conversion observed only after a floating loop must not add work to
69
97
  // each iteration. Expression results still carry their existing views.
70
98
  fn.body.every(stmt);
99
+ for (const id of compared)
100
+ if (declared.has(id) && !nonBitwise.has(id))
101
+ wanted.add(id);
71
102
  const eligible = new Set(fn.locals
72
103
  .filter((local) => local.type.kind === "f64" &&
73
104
  !local.boxed &&
@@ -80,4 +111,18 @@ export function findIntegerViews(fn) {
80
111
  wanted.delete(id);
81
112
  return wanted;
82
113
  }
114
+ const COMPARES = new Set(["===", "!==", "<", "<=", ">", ">="]);
115
+ /** Whether a value is always a bitwise result, whose ToUint32 view is free. */
116
+ function bitwiseValue(value) {
117
+ if (value.kind === "bin")
118
+ return (value.op === "&" ||
119
+ value.op === "|" ||
120
+ value.op === "^" ||
121
+ value.op === "<<" ||
122
+ value.op === ">>" ||
123
+ value.op === ">>>");
124
+ if (value.kind === "unary")
125
+ return value.op === "~";
126
+ return value.kind === "libCall" && (value.fn === "math.imul" || value.fn === "math.clz32");
127
+ }
83
128
  //# sourceMappingURL=integer-views.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"integer-views.js","sourceRoot":"","sources":["../../../src/backend/llvm/integer-views.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"integer-views.js","sourceRoot":"","sources":["../../../src/backend/llvm/integer-views.ts"],"names":[],"mappings":"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"}
@@ -7,7 +7,23 @@ import type { IrFunction } from "../../ir/ir.js";
7
7
  export declare class LazyCaptures {
8
8
  private readonly functions;
9
9
  private readonly unchanged;
10
+ private readonly stable;
11
+ private readonly once;
12
+ private sites;
10
13
  constructor(functions: ReadonlyMap<string, IrFunction>);
14
+ /** The captures of closure body `fnName` that hold one value for the
15
+ * closure's whole life: at every creation site the captured binding is
16
+ * a parameter that nothing rebinds (see parameters) or, through nesting,
17
+ * such a capture of the creating closure, and nothing rebinds the
18
+ * capture itself. The environment owns that value whenever the body
19
+ * runs, so the body may read it without a reference of its own. */
20
+ stableCaptures(fnName: string): Set<string>;
21
+ /** Boxed locals of `fn` (not parameters) bound by exactly one
22
+ * declaration that nothing else rebinds, here or in nested bodies. Each
23
+ * declaration fills a fresh box once, before any closure can capture it
24
+ * (TDZ bindings are excluded). */
25
+ private declaredOnce;
26
+ private creationSites;
11
27
  parameters(fn: IrFunction): Set<string>;
12
28
  /** The subset of `ids` rebound in `fn` or in any function that captures
13
29
  * one of them, directly or through further nesting. */