@scriptc/compiler 0.4.8 → 0.4.9

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 (536) hide show
  1. package/ambient/node-fallback/buffer.d.ts +2 -0
  2. package/ambient/node-fallback/child_process.d.ts +9 -3
  3. package/ambient/node-fallback/dns-promises.d.ts +25 -0
  4. package/ambient/node-fallback/dns.d.ts +29 -0
  5. package/ambient/node-fallback/test.d.ts +7 -0
  6. package/ambient/scriptc-node-fallback.d.ts +145 -2
  7. package/ambient/scriptc-overrides.d.ts +22 -13
  8. package/dist/backend/build-cache.d.ts +1 -1
  9. package/dist/backend/build-cache.js +1 -1
  10. package/dist/backend/build-cache.js.map +1 -1
  11. package/dist/backend/cache-root.d.ts +7 -0
  12. package/dist/backend/cache-root.js +27 -0
  13. package/dist/backend/cache-root.js.map +1 -1
  14. package/dist/backend/executable-features.js +5 -1
  15. package/dist/backend/executable-features.js.map +1 -1
  16. package/dist/backend/link-plan.js +7 -1
  17. package/dist/backend/link-plan.js.map +1 -1
  18. package/dist/backend/llvm/bytes-loop-versions.d.ts +12 -1
  19. package/dist/backend/llvm/bytes-loop-versions.js +107 -30
  20. package/dist/backend/llvm/bytes-loop-versions.js.map +1 -1
  21. package/dist/backend/llvm/bytes-loop-versions.test.js +96 -0
  22. package/dist/backend/llvm/bytes-loop-versions.test.js.map +1 -1
  23. package/dist/backend/llvm/checked-value-lifetimes.js +1 -0
  24. package/dist/backend/llvm/checked-value-lifetimes.js.map +1 -1
  25. package/dist/backend/llvm/classes.d.ts +16 -5
  26. package/dist/backend/llvm/classes.js +34 -6
  27. package/dist/backend/llvm/classes.js.map +1 -1
  28. package/dist/backend/llvm/classes.test.js +21 -2
  29. package/dist/backend/llvm/classes.test.js.map +1 -1
  30. package/dist/backend/llvm/common.d.ts +9 -0
  31. package/dist/backend/llvm/common.js +9 -0
  32. package/dist/backend/llvm/common.js.map +1 -1
  33. package/dist/backend/llvm/cpu-dispatch.d.ts +36 -2
  34. package/dist/backend/llvm/cpu-dispatch.js +96 -2
  35. package/dist/backend/llvm/cpu-dispatch.js.map +1 -1
  36. package/dist/backend/llvm/dense-array-access.d.ts +5 -2
  37. package/dist/backend/llvm/dense-array-access.js +16 -12
  38. package/dist/backend/llvm/dense-array-access.js.map +1 -1
  39. package/dist/backend/llvm/dense-array-access.test.js +3 -1
  40. package/dist/backend/llvm/dense-array-access.test.js.map +1 -1
  41. package/dist/backend/llvm/dyn.d.ts +24 -0
  42. package/dist/backend/llvm/dyn.js +117 -3
  43. package/dist/backend/llvm/dyn.js.map +1 -1
  44. package/dist/backend/llvm/emit-function.js +6 -0
  45. package/dist/backend/llvm/emit-function.js.map +1 -1
  46. package/dist/backend/llvm/emit-journal.d.ts +1 -0
  47. package/dist/backend/llvm/emit-journal.js.map +1 -1
  48. package/dist/backend/llvm/emit-module.js +48 -5
  49. package/dist/backend/llvm/emit-module.js.map +1 -1
  50. package/dist/backend/llvm/emit-module.test.js +41 -0
  51. package/dist/backend/llvm/emit-module.test.js.map +1 -1
  52. package/dist/backend/llvm/emit-statements.js +11 -0
  53. package/dist/backend/llvm/emit-statements.js.map +1 -1
  54. package/dist/backend/llvm/emitter.d.ts +87 -7
  55. package/dist/backend/llvm/emitter.js +136 -15
  56. package/dist/backend/llvm/emitter.js.map +1 -1
  57. package/dist/backend/llvm/expr-async.js +28 -6
  58. package/dist/backend/llvm/expr-async.js.map +1 -1
  59. package/dist/backend/llvm/expr-containers.js +19 -5
  60. package/dist/backend/llvm/expr-containers.js.map +1 -1
  61. package/dist/backend/llvm/expr-dynamic.js +29 -1
  62. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  63. package/dist/backend/llvm/expr-primitives.js +104 -6
  64. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  65. package/dist/backend/llvm/expr-records.js +15 -1
  66. package/dist/backend/llvm/expr-records.js.map +1 -1
  67. package/dist/backend/llvm/expr-stream-bridges.js +53 -5
  68. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  69. package/dist/backend/llvm/inline-arrays.js +1 -1
  70. package/dist/backend/llvm/inline-arrays.js.map +1 -1
  71. package/dist/backend/llvm/js-ic.js +126 -2
  72. package/dist/backend/llvm/js-ic.js.map +1 -1
  73. package/dist/backend/llvm/lanes.d.ts +38 -0
  74. package/dist/backend/llvm/lanes.js +778 -0
  75. package/dist/backend/llvm/lanes.js.map +1 -0
  76. package/dist/backend/llvm/lanes.test.d.ts +1 -0
  77. package/dist/backend/llvm/lanes.test.js +402 -0
  78. package/dist/backend/llvm/lanes.test.js.map +1 -0
  79. package/dist/backend/llvm/lib-dispatch.js +9 -4
  80. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  81. package/dist/backend/llvm/lib-network.js +20 -0
  82. package/dist/backend/llvm/lib-network.js.map +1 -1
  83. package/dist/backend/llvm/lib-shared.js +27 -0
  84. package/dist/backend/llvm/lib-shared.js.map +1 -1
  85. package/dist/backend/llvm/lib-test.js +11 -0
  86. package/dist/backend/llvm/lib-test.js.map +1 -1
  87. package/dist/backend/llvm/local-array-reads.js +2 -2
  88. package/dist/backend/llvm/local-array-reads.js.map +1 -1
  89. package/dist/backend/llvm/map-number-lookup.js +8 -2
  90. package/dist/backend/llvm/map-number-lookup.js.map +1 -1
  91. package/dist/backend/llvm/nullable-unions.js +5 -2
  92. package/dist/backend/llvm/nullable-unions.js.map +1 -1
  93. package/dist/backend/llvm/publish.d.ts +3 -0
  94. package/dist/backend/llvm/publish.js +2 -2
  95. package/dist/backend/llvm/publish.js.map +1 -1
  96. package/dist/backend/llvm/reference-writes.js +1 -0
  97. package/dist/backend/llvm/reference-writes.js.map +1 -1
  98. package/dist/backend/llvm/region-groups.js +43 -4
  99. package/dist/backend/llvm/region-groups.js.map +1 -1
  100. package/dist/backend/llvm/region-groups.test.js +79 -0
  101. package/dist/backend/llvm/region-groups.test.js.map +1 -1
  102. package/dist/backend/llvm/runtime-registries.test.js +32 -1
  103. package/dist/backend/llvm/runtime-registries.test.js.map +1 -1
  104. package/dist/backend/llvm/shapes.js +10 -1
  105. package/dist/backend/llvm/shapes.js.map +1 -1
  106. package/dist/backend/llvm/string-reads.d.ts +1 -1
  107. package/dist/backend/llvm/string-reads.js +1 -1
  108. package/dist/backend/llvm/string-reads.js.map +1 -1
  109. package/dist/backend/llvm/unwind-abi.js +24 -2
  110. package/dist/backend/llvm/unwind-abi.js.map +1 -1
  111. package/dist/backend/llvm/unwind-abi.test.js +38 -0
  112. package/dist/backend/llvm/unwind-abi.test.js.map +1 -1
  113. package/dist/backend/llvm/walkers.d.ts +3 -0
  114. package/dist/backend/llvm/walkers.js +20 -2
  115. package/dist/backend/llvm/walkers.js.map +1 -1
  116. package/dist/backend/native/contracts.d.ts +15 -3
  117. package/dist/backend/native/executable.js +19 -5
  118. package/dist/backend/native/executable.js.map +1 -1
  119. package/dist/backend/native-codegen-core.d.ts +20 -0
  120. package/dist/backend/native-codegen-core.js +15 -0
  121. package/dist/backend/native-codegen-core.js.map +1 -1
  122. package/dist/backend/native-codegen.d.ts +5 -0
  123. package/dist/backend/native-codegen.js +62 -8
  124. package/dist/backend/native-codegen.js.map +1 -1
  125. package/dist/backend/native-codegen.test.js +48 -8
  126. package/dist/backend/native-codegen.test.js.map +1 -1
  127. package/dist/backend/native-link-info-core.d.ts +27 -3
  128. package/dist/backend/native-link-info-core.js.map +1 -1
  129. package/dist/backend/native-link-info.test.js +17 -1
  130. package/dist/backend/native-link-info.test.js.map +1 -1
  131. package/dist/backend/native-toolchain.d.ts +1 -1
  132. package/dist/backend/native-toolchain.js +1 -1
  133. package/dist/backend/native-toolchain.js.map +1 -1
  134. package/dist/backend/native-toolchain.test.js +14 -1
  135. package/dist/backend/native-toolchain.test.js.map +1 -1
  136. package/dist/backend/runtime-pack-core.d.ts +9 -3
  137. package/dist/backend/runtime-pack-core.js +6 -1
  138. package/dist/backend/runtime-pack-core.js.map +1 -1
  139. package/dist/backend/runtime-pack.test.js +32 -1
  140. package/dist/backend/runtime-pack.test.js.map +1 -1
  141. package/dist/backend/targets.d.ts +9 -1
  142. package/dist/backend/targets.js +11 -2
  143. package/dist/backend/targets.js.map +1 -1
  144. package/dist/backend/targets.test.js +6 -0
  145. package/dist/backend/targets.test.js.map +1 -1
  146. package/dist/cli/command.js +15 -1
  147. package/dist/cli/command.js.map +1 -1
  148. package/dist/cli/host.d.ts +6 -0
  149. package/dist/cli/mcp.d.ts +72 -0
  150. package/dist/cli/mcp.js +601 -0
  151. package/dist/cli/mcp.js.map +1 -0
  152. package/dist/cli/mcp.test.d.ts +1 -0
  153. package/dist/cli/mcp.test.js +380 -0
  154. package/dist/cli/mcp.test.js.map +1 -0
  155. package/dist/cli/output-options.d.ts +1 -0
  156. package/dist/cli/output-options.js +3 -0
  157. package/dist/cli/output-options.js.map +1 -1
  158. package/dist/cli/usage.d.ts +51 -1
  159. package/dist/cli/usage.js +709 -186
  160. package/dist/cli/usage.js.map +1 -1
  161. package/dist/compat/fetch-profile.js +9 -4
  162. package/dist/compat/fetch-profile.js.map +1 -1
  163. package/dist/compile-types.d.ts +17 -0
  164. package/dist/coverage/report.d.ts +5 -9
  165. package/dist/coverage/report.js.map +1 -1
  166. package/dist/executable/executable-cache.d.ts +17 -3
  167. package/dist/executable/executable-cache.js +17 -3
  168. package/dist/executable/executable-cache.js.map +1 -1
  169. package/dist/executable/prepare.js +87 -10
  170. package/dist/executable/prepare.js.map +1 -1
  171. package/dist/frontend/analysis.js +3 -2
  172. package/dist/frontend/analysis.js.map +1 -1
  173. package/dist/frontend/canon-map.js +13 -8
  174. package/dist/frontend/canon-map.js.map +1 -1
  175. package/dist/frontend/decl-projection.d.ts +18 -0
  176. package/dist/frontend/decl-projection.js +90 -22
  177. package/dist/frontend/decl-projection.js.map +1 -1
  178. package/dist/frontend/decl-projection.test.js +47 -1
  179. package/dist/frontend/decl-projection.test.js.map +1 -1
  180. package/dist/frontend/default-library.d.ts +10 -0
  181. package/dist/frontend/default-library.js +43 -0
  182. package/dist/frontend/default-library.js.map +1 -0
  183. package/dist/frontend/fork-target.js +54 -9
  184. package/dist/frontend/fork-target.js.map +1 -1
  185. package/dist/frontend/fork-target.test.js +82 -0
  186. package/dist/frontend/fork-target.test.js.map +1 -1
  187. package/dist/frontend/inferred-js-diagnostics.test.js +73 -0
  188. package/dist/frontend/inferred-js-diagnostics.test.js.map +1 -1
  189. package/dist/frontend/lowering/abstract-equality.d.ts +2 -1
  190. package/dist/frontend/lowering/abstract-equality.js +7 -1
  191. package/dist/frontend/lowering/abstract-equality.js.map +1 -1
  192. package/dist/frontend/lowering/array-values.js +2 -2
  193. package/dist/frontend/lowering/array-values.js.map +1 -1
  194. package/dist/frontend/lowering/assertion-members.js +52 -2
  195. package/dist/frontend/lowering/assertion-members.js.map +1 -1
  196. package/dist/frontend/lowering/builtin-namespaces.d.ts +5 -0
  197. package/dist/frontend/lowering/builtin-namespaces.js +19 -12
  198. package/dist/frontend/lowering/builtin-namespaces.js.map +1 -1
  199. package/dist/frontend/lowering/builtins/callable-aliases.js +42 -6
  200. package/dist/frontend/lowering/builtins/callable-aliases.js.map +1 -1
  201. package/dist/frontend/lowering/builtins/child-process.d.ts +12 -11
  202. package/dist/frontend/lowering/builtins/child-process.js +235 -38
  203. package/dist/frontend/lowering/builtins/child-process.js.map +1 -1
  204. package/dist/frontend/lowering/builtins/compression.d.ts +6 -1
  205. package/dist/frontend/lowering/builtins/compression.js +3 -3
  206. package/dist/frontend/lowering/builtins/compression.js.map +1 -1
  207. package/dist/frontend/lowering/builtins/constants.js +2 -2
  208. package/dist/frontend/lowering/builtins/constants.js.map +1 -1
  209. package/dist/frontend/lowering/builtins/crypto.d.ts +3 -1
  210. package/dist/frontend/lowering/builtins/crypto.js +9 -1
  211. package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
  212. package/dist/frontend/lowering/builtins/dates.js +26 -6
  213. package/dist/frontend/lowering/builtins/dates.js.map +1 -1
  214. package/dist/frontend/lowering/builtins/environment.d.ts +13 -1
  215. package/dist/frontend/lowering/builtins/environment.js +15 -4
  216. package/dist/frontend/lowering/builtins/environment.js.map +1 -1
  217. package/dist/frontend/lowering/builtins/module-bindings.d.ts +33 -0
  218. package/dist/frontend/lowering/builtins/module-bindings.js +213 -11
  219. package/dist/frontend/lowering/builtins/module-bindings.js.map +1 -1
  220. package/dist/frontend/lowering/builtins/module-resolution.d.ts +9 -2
  221. package/dist/frontend/lowering/builtins/module-resolution.js +187 -19
  222. package/dist/frontend/lowering/builtins/module-resolution.js.map +1 -1
  223. package/dist/frontend/lowering/builtins/performance.js +1 -1
  224. package/dist/frontend/lowering/builtins/performance.js.map +1 -1
  225. package/dist/frontend/lowering/builtins/process.js +40 -2
  226. package/dist/frontend/lowering/builtins/process.js.map +1 -1
  227. package/dist/frontend/lowering/builtins/promises.js +33 -0
  228. package/dist/frontend/lowering/builtins/promises.js.map +1 -1
  229. package/dist/frontend/lowering/builtins/readline.d.ts +9 -5
  230. package/dist/frontend/lowering/builtins/readline.js +184 -75
  231. package/dist/frontend/lowering/builtins/readline.js.map +1 -1
  232. package/dist/frontend/lowering/builtins/url.d.ts +4 -0
  233. package/dist/frontend/lowering/builtins/url.js +6 -0
  234. package/dist/frontend/lowering/builtins/url.js.map +1 -1
  235. package/dist/frontend/lowering/call-arguments.js +15 -0
  236. package/dist/frontend/lowering/call-arguments.js.map +1 -1
  237. package/dist/frontend/lowering/callable-properties.d.ts +34 -0
  238. package/dist/frontend/lowering/callable-properties.js +210 -0
  239. package/dist/frontend/lowering/callable-properties.js.map +1 -0
  240. package/dist/frontend/lowering/cjs-inline-require.d.ts +16 -0
  241. package/dist/frontend/lowering/cjs-inline-require.js +105 -0
  242. package/dist/frontend/lowering/cjs-inline-require.js.map +1 -1
  243. package/dist/frontend/lowering/cjs-inline-require.test.d.ts +1 -0
  244. package/dist/frontend/lowering/cjs-inline-require.test.js +61 -0
  245. package/dist/frontend/lowering/cjs-inline-require.test.js.map +1 -0
  246. package/dist/frontend/lowering/class-dynamic-dispatch.js +82 -2
  247. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  248. package/dist/frontend/lowering/class-protocols.d.ts +57 -4
  249. package/dist/frontend/lowering/class-protocols.js +597 -30
  250. package/dist/frontend/lowering/class-protocols.js.map +1 -1
  251. package/dist/frontend/lowering/class-unions.js +2 -2
  252. package/dist/frontend/lowering/class-unions.js.map +1 -1
  253. package/dist/frontend/lowering/coercions/function-adapters.d.ts +12 -0
  254. package/dist/frontend/lowering/coercions/function-adapters.js +62 -0
  255. package/dist/frontend/lowering/coercions/function-adapters.js.map +1 -1
  256. package/dist/frontend/lowering/coercions/structural-plans.js +56 -1
  257. package/dist/frontend/lowering/coercions/structural-plans.js.map +1 -1
  258. package/dist/frontend/lowering/coercions/structural.js +9 -4
  259. package/dist/frontend/lowering/coercions/structural.js.map +1 -1
  260. package/dist/frontend/lowering/collection-ingestion.d.ts +9 -0
  261. package/dist/frontend/lowering/collection-ingestion.js +115 -41
  262. package/dist/frontend/lowering/collection-ingestion.js.map +1 -1
  263. package/dist/frontend/lowering/containers/array-callbacks.js +16 -0
  264. package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
  265. package/dist/frontend/lowering/containers/bytes.js +66 -10
  266. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  267. package/dist/frontend/lowering/containers/collection-methods.js +61 -5
  268. package/dist/frontend/lowering/containers/collection-methods.js.map +1 -1
  269. package/dist/frontend/lowering/containers/filter-predicates.js +11 -0
  270. package/dist/frontend/lowering/containers/filter-predicates.js.map +1 -1
  271. package/dist/frontend/lowering/containers/indexed-objects.d.ts +15 -0
  272. package/dist/frontend/lowering/containers/indexed-objects.js +213 -30
  273. package/dist/frontend/lowering/containers/indexed-objects.js.map +1 -1
  274. package/dist/frontend/lowering/error-name-order.d.ts +16 -0
  275. package/dist/frontend/lowering/error-name-order.js +61 -0
  276. package/dist/frontend/lowering/error-name-order.js.map +1 -1
  277. package/dist/frontend/lowering/expressions/asserted-receiver.d.ts +17 -0
  278. package/dist/frontend/lowering/expressions/asserted-receiver.js +123 -1
  279. package/dist/frontend/lowering/expressions/asserted-receiver.js.map +1 -1
  280. package/dist/frontend/lowering/expressions/binary.js +147 -20
  281. package/dist/frontend/lowering/expressions/binary.js.map +1 -1
  282. package/dist/frontend/lowering/expressions/element-access.js +63 -14
  283. package/dist/frontend/lowering/expressions/element-access.js.map +1 -1
  284. package/dist/frontend/lowering/expressions/erased-delete.d.ts +59 -0
  285. package/dist/frontend/lowering/expressions/erased-delete.js +247 -0
  286. package/dist/frontend/lowering/expressions/erased-delete.js.map +1 -0
  287. package/dist/frontend/lowering/expressions/hosted-narrowing.d.ts +10 -0
  288. package/dist/frontend/lowering/expressions/hosted-narrowing.js +48 -1
  289. package/dist/frontend/lowering/expressions/hosted-narrowing.js.map +1 -1
  290. package/dist/frontend/lowering/expressions/identifiers.js +20 -0
  291. package/dist/frontend/lowering/expressions/identifiers.js.map +1 -1
  292. package/dist/frontend/lowering/expressions/narrowing.d.ts +7 -2
  293. package/dist/frontend/lowering/expressions/narrowing.js +77 -45
  294. package/dist/frontend/lowering/expressions/narrowing.js.map +1 -1
  295. package/dist/frontend/lowering/expressions/object-literals.js +62 -19
  296. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  297. package/dist/frontend/lowering/expressions/optional-chains.js +19 -0
  298. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  299. package/dist/frontend/lowering/expressions/property-access.d.ts +7 -7
  300. package/dist/frontend/lowering/expressions/property-access.js +247 -48
  301. package/dist/frontend/lowering/expressions/property-access.js.map +1 -1
  302. package/dist/frontend/lowering/expressions/relational.d.ts +1 -0
  303. package/dist/frontend/lowering/expressions/relational.js +18 -8
  304. package/dist/frontend/lowering/expressions/relational.js.map +1 -1
  305. package/dist/frontend/lowering/expressions/union-fields.js +11 -5
  306. package/dist/frontend/lowering/expressions/union-fields.js.map +1 -1
  307. package/dist/frontend/lowering/expressions/updates.js +121 -11
  308. package/dist/frontend/lowering/expressions/updates.js.map +1 -1
  309. package/dist/frontend/lowering/function-context.d.ts +10 -0
  310. package/dist/frontend/lowering/function-context.js +36 -0
  311. package/dist/frontend/lowering/function-context.js.map +1 -1
  312. package/dist/frontend/lowering/function-returns.js +8 -8
  313. package/dist/frontend/lowering/function-returns.js.map +1 -1
  314. package/dist/frontend/lowering/handle-properties.d.ts +62 -3
  315. package/dist/frontend/lowering/handle-properties.js +674 -26
  316. package/dist/frontend/lowering/handle-properties.js.map +1 -1
  317. package/dist/frontend/lowering/handle-properties.test.js +95 -2
  318. package/dist/frontend/lowering/handle-properties.test.js.map +1 -1
  319. package/dist/frontend/lowering/lower-builtin-values.d.ts +12 -0
  320. package/dist/frontend/lowering/lower-builtin-values.js +44 -0
  321. package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
  322. package/dist/frontend/lowering/lower-calls.js +328 -136
  323. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  324. package/dist/frontend/lowering/lower-classes.js +82 -17
  325. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  326. package/dist/frontend/lowering/lower-event-emitter.js +113 -9
  327. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  328. package/dist/frontend/lowering/lower-expando.d.ts +13 -21
  329. package/dist/frontend/lowering/lower-expando.js +90 -126
  330. package/dist/frontend/lowering/lower-expando.js.map +1 -1
  331. package/dist/frontend/lowering/lower-exprs.js +2 -2
  332. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  333. package/dist/frontend/lowering/lower-functions.js +65 -0
  334. package/dist/frontend/lowering/lower-functions.js.map +1 -1
  335. package/dist/frontend/lowering/lower-inspect.js +471 -0
  336. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  337. package/dist/frontend/lowering/lower-modules.js +36 -10
  338. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  339. package/dist/frontend/lowering/lower-node-island.js +28 -0
  340. package/dist/frontend/lowering/lower-node-island.js.map +1 -1
  341. package/dist/frontend/lowering/lower-server.d.ts +53 -7
  342. package/dist/frontend/lowering/lower-server.js +213 -42
  343. package/dist/frontend/lowering/lower-server.js.map +1 -1
  344. package/dist/frontend/lowering/lower-stdlib.js +50 -7
  345. package/dist/frontend/lowering/lower-stdlib.js.map +1 -1
  346. package/dist/frontend/lowering/lower-stmts.d.ts +24 -0
  347. package/dist/frontend/lowering/lower-stmts.js +463 -220
  348. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  349. package/dist/frontend/lowering/lower-stream.js +2 -2
  350. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  351. package/dist/frontend/lowering/lower-test.js +71 -2
  352. package/dist/frontend/lowering/lower-test.js.map +1 -1
  353. package/dist/frontend/lowering/lowerer.d.ts +81 -10
  354. package/dist/frontend/lowering/lowerer.js +319 -72
  355. package/dist/frontend/lowering/lowerer.js.map +1 -1
  356. package/dist/frontend/lowering/new-target.js +10 -2
  357. package/dist/frontend/lowering/new-target.js.map +1 -1
  358. package/dist/frontend/lowering/nullish-empty-pattern.js +3 -3
  359. package/dist/frontend/lowering/nullish-empty-pattern.js.map +1 -1
  360. package/dist/frontend/lowering/partial-assertions.js +30 -5
  361. package/dist/frontend/lowering/partial-assertions.js.map +1 -1
  362. package/dist/frontend/lowering/primitive-throws.js +91 -1
  363. package/dist/frontend/lowering/primitive-throws.js.map +1 -1
  364. package/dist/frontend/lowering/primitive-wrappers.d.ts +9 -0
  365. package/dist/frontend/lowering/primitive-wrappers.js +2 -2
  366. package/dist/frontend/lowering/primitive-wrappers.js.map +1 -1
  367. package/dist/frontend/lowering/promise-executor-adapter.js +5 -2
  368. package/dist/frontend/lowering/promise-executor-adapter.js.map +1 -1
  369. package/dist/frontend/lowering/record-links.js +7 -2
  370. package/dist/frontend/lowering/record-links.js.map +1 -1
  371. package/dist/frontend/lowering/surfaces.d.ts +4 -0
  372. package/dist/frontend/lowering/surfaces.js +118 -2
  373. package/dist/frontend/lowering/surfaces.js.map +1 -1
  374. package/dist/frontend/lowering/surfaces.test.d.ts +1 -0
  375. package/dist/frontend/lowering/surfaces.test.js +31 -0
  376. package/dist/frontend/lowering/surfaces.test.js.map +1 -0
  377. package/dist/frontend/mock-shapes.js +3 -3
  378. package/dist/frontend/mock-shapes.js.map +1 -1
  379. package/dist/frontend/npm-static-ladder.d.ts +21 -0
  380. package/dist/frontend/npm-static-ladder.js +2 -0
  381. package/dist/frontend/npm-static-ladder.js.map +1 -0
  382. package/dist/frontend/npm-static-ladder.test.d.ts +1 -0
  383. package/dist/frontend/npm-static-ladder.test.js +138 -0
  384. package/dist/frontend/npm-static-ladder.test.js.map +1 -0
  385. package/dist/frontend/npm-static-status.d.ts +15 -0
  386. package/dist/frontend/npm-static-status.js +2 -0
  387. package/dist/frontend/npm-static-status.js.map +1 -0
  388. package/dist/frontend/package-shims.js +1 -1
  389. package/dist/frontend/package-shims.js.map +1 -1
  390. package/dist/frontend/pipeline.d.ts +1 -1
  391. package/dist/frontend/pipeline.js +222 -25
  392. package/dist/frontend/pipeline.js.map +1 -1
  393. package/dist/frontend/program-analysis.d.ts +4 -0
  394. package/dist/frontend/program-analysis.js +6 -0
  395. package/dist/frontend/program-analysis.js.map +1 -1
  396. package/dist/frontend/program.js +258 -32
  397. package/dist/frontend/program.js.map +1 -1
  398. package/dist/frontend/program.test.js +30 -0
  399. package/dist/frontend/program.test.js.map +1 -1
  400. package/dist/frontend/resolve.js +29 -5
  401. package/dist/frontend/resolve.js.map +1 -1
  402. package/dist/frontend/resolve.test.js +40 -0
  403. package/dist/frontend/resolve.test.js.map +1 -1
  404. package/dist/frontend/services.d.ts +8 -0
  405. package/dist/frontend/services.js +7 -0
  406. package/dist/frontend/services.js.map +1 -1
  407. package/dist/frontend/ts7/checker.d.ts +7 -0
  408. package/dist/frontend/ts7/checker.js +12 -0
  409. package/dist/frontend/ts7/checker.js.map +1 -1
  410. package/dist/frontend/ts7/checker.test.js +1 -0
  411. package/dist/frontend/ts7/checker.test.js.map +1 -1
  412. package/dist/frontend/ts7/program-host.d.ts +39 -2
  413. package/dist/frontend/ts7/program-host.js +62 -8
  414. package/dist/frontend/ts7/program-host.js.map +1 -1
  415. package/dist/frontend/ts7/program-host.test.js +33 -0
  416. package/dist/frontend/ts7/program-host.test.js.map +1 -1
  417. package/dist/frontend/ts7/session-cache.d.ts +5 -1
  418. package/dist/frontend/ts7/session-cache.js +7 -1
  419. package/dist/frontend/ts7/session-cache.js.map +1 -1
  420. package/dist/frontend/ts7/session-cache.test.js +37 -0
  421. package/dist/frontend/ts7/session-cache.test.js.map +1 -1
  422. package/dist/frontend/ts7/session.js +19 -1
  423. package/dist/frontend/ts7/session.js.map +1 -1
  424. package/dist/frontend/ts7/source-parser.d.ts +17 -2
  425. package/dist/frontend/ts7/source-parser.js +61 -2
  426. package/dist/frontend/ts7/source-parser.js.map +1 -1
  427. package/dist/frontend/ts7/source-parser.test.js +55 -2
  428. package/dist/frontend/ts7/source-parser.test.js.map +1 -1
  429. package/dist/frontend/tsc-codes.d.ts +3 -2
  430. package/dist/frontend/tsc-codes.js +129 -22
  431. package/dist/frontend/tsc-codes.js.map +1 -1
  432. package/dist/frontend/type-mapper.d.ts +5 -11
  433. package/dist/frontend/type-mapper.js +380 -70
  434. package/dist/frontend/type-mapper.js.map +1 -1
  435. package/dist/index.d.ts +1 -1
  436. package/dist/index.js +67 -7
  437. package/dist/index.js.map +1 -1
  438. package/dist/ir/builtin-effects.js +29 -0
  439. package/dist/ir/builtin-effects.js.map +1 -1
  440. package/dist/ir/builtin-signatures.d.ts +1 -1
  441. package/dist/ir/builtin-signatures.js +72 -6
  442. package/dist/ir/builtin-signatures.js.map +1 -1
  443. package/dist/ir/codec.generated.d.ts +1 -1
  444. package/dist/ir/codec.generated.js +321 -263
  445. package/dist/ir/codec.generated.js.map +1 -1
  446. package/dist/ir/constant-length-clones.d.ts +26 -0
  447. package/dist/ir/constant-length-clones.js +589 -0
  448. package/dist/ir/constant-length-clones.js.map +1 -0
  449. package/dist/ir/constant-length-clones.test.d.ts +1 -0
  450. package/dist/ir/constant-length-clones.test.js +292 -0
  451. package/dist/ir/constant-length-clones.test.js.map +1 -0
  452. package/dist/ir/constant-tables.d.ts +10 -5
  453. package/dist/ir/constant-tables.js +83 -17
  454. package/dist/ir/constant-tables.js.map +1 -1
  455. package/dist/ir/constant-tables.test.js +58 -1
  456. package/dist/ir/constant-tables.test.js.map +1 -1
  457. package/dist/ir/fields.generated.js +5 -2
  458. package/dist/ir/fields.generated.js.map +1 -1
  459. package/dist/ir/function-references.js +2 -0
  460. package/dist/ir/function-references.js.map +1 -1
  461. package/dist/ir/function-references.test.js +13 -0
  462. package/dist/ir/function-references.test.js.map +1 -1
  463. package/dist/ir/integer-loops.js +1 -0
  464. package/dist/ir/integer-loops.js.map +1 -1
  465. package/dist/ir/integer-loops.test.js +16 -0
  466. package/dist/ir/integer-loops.test.js.map +1 -1
  467. package/dist/ir/ir.d.ts +50 -6
  468. package/dist/ir/ir.js +44 -2
  469. package/dist/ir/ir.js.map +1 -1
  470. package/dist/ir/ir.test.js +83 -1
  471. package/dist/ir/ir.test.js.map +1 -1
  472. package/dist/ir/js-groups.js +5 -1
  473. package/dist/ir/js-groups.js.map +1 -1
  474. package/dist/ir/js-ic.d.ts +20 -0
  475. package/dist/ir/js-ic.js +81 -4
  476. package/dist/ir/js-ic.js.map +1 -1
  477. package/dist/ir/js-ic.test.js +8 -1
  478. package/dist/ir/js-ic.test.js.map +1 -1
  479. package/dist/ir/lane-plans.d.ts +86 -0
  480. package/dist/ir/lane-plans.js +589 -0
  481. package/dist/ir/lane-plans.js.map +1 -0
  482. package/dist/ir/lane-plans.test.d.ts +1 -0
  483. package/dist/ir/lane-plans.test.js +549 -0
  484. package/dist/ir/lane-plans.test.js.map +1 -0
  485. package/dist/ir/runtime-features.d.ts +68 -10
  486. package/dist/ir/runtime-features.js +285 -17
  487. package/dist/ir/runtime-features.js.map +1 -1
  488. package/dist/ir/runtime-features.test.js +190 -1
  489. package/dist/ir/runtime-features.test.js.map +1 -1
  490. package/dist/ir/validate.js +61 -24
  491. package/dist/ir/validate.js.map +1 -1
  492. package/dist/native/cache.d.ts +5 -0
  493. package/dist/native/cache.js +23 -1
  494. package/dist/native/cache.js.map +1 -1
  495. package/dist/native/cache.test.js +29 -1
  496. package/dist/native/cache.test.js.map +1 -1
  497. package/dist/native/cli.js +4 -2
  498. package/dist/native/cli.js.map +1 -1
  499. package/dist/native/compiler.d.ts +11 -3
  500. package/dist/native/compiler.js +102 -16
  501. package/dist/native/compiler.js.map +1 -1
  502. package/dist/native/compiler.test.js +244 -2
  503. package/dist/native/compiler.test.js.map +1 -1
  504. package/dist/native/prepare.d.ts +14 -1
  505. package/dist/native/prepare.js +79 -29
  506. package/dist/native/prepare.js.map +1 -1
  507. package/dist/native/sanitizer.test.js +3 -0
  508. package/dist/native/sanitizer.test.js.map +1 -1
  509. package/dist/native/unchanged.d.ts +80 -0
  510. package/dist/native/unchanged.js +301 -0
  511. package/dist/native/unchanged.js.map +1 -0
  512. package/dist/native/unchanged.test.d.ts +1 -0
  513. package/dist/native/unchanged.test.js +249 -0
  514. package/dist/native/unchanged.test.js.map +1 -0
  515. package/dist/node-islands/boundary.d.ts +16 -0
  516. package/dist/node-islands/boundary.js +70 -7
  517. package/dist/node-islands/boundary.js.map +1 -1
  518. package/dist/node-islands/boundary.test.js +59 -14
  519. package/dist/node-islands/boundary.test.js.map +1 -1
  520. package/dist/node-islands/detect.js +203 -47
  521. package/dist/node-islands/detect.js.map +1 -1
  522. package/dist/node-islands/detect.test.js +45 -0
  523. package/dist/node-islands/detect.test.js.map +1 -1
  524. package/dist/node-islands/growth.js +4 -16
  525. package/dist/node-islands/growth.js.map +1 -1
  526. package/dist/node-islands/modules.d.ts +3 -0
  527. package/dist/node-islands/modules.js +143 -12
  528. package/dist/node-islands/modules.js.map +1 -1
  529. package/dist/node-islands/modules.test.js +125 -0
  530. package/dist/node-islands/modules.test.js.map +1 -1
  531. package/dist/node-islands/report.d.ts +1 -1
  532. package/dist/node-islands/report.js +2 -1
  533. package/dist/node-islands/report.js.map +1 -1
  534. package/package.json +20 -20
  535. package/shims/undici/core/request.ts +7 -1
  536. package/surface-manifest.json +380 -2
@@ -0,0 +1,778 @@
1
+ /* Lane loops: the `elementwise` lane plans of ir/lane-plans.ts, lowered to
2
+ * LLVM vector IR.
3
+ *
4
+ * A planned loop keeps its scalar form. The emitter adds, before the loop's
5
+ * copies, an entry guard and a lane loop:
6
+ *
7
+ * guard: SCRIPTC_LANES is on, at least one whole vector is left, and (for
8
+ * a sum) the element count is below the bound that makes every
9
+ * partial sum an exact double;
10
+ * lanes: load <W x iN> at the element index, widen to <W x i64>, fold;
11
+ * exit: add the folded lanes to the accumulator once and leave the
12
+ * induction at the lane loop's limit.
13
+ *
14
+ * The false edge of the guard, and the induction the lane loop leaves behind,
15
+ * are the loop's own scalar code, unchanged: the loop's copies start at the
16
+ * current induction, so they run the elements the lanes left over. The
17
+ * accumulator is read from its slot after the last lane iteration (the scalar
18
+ * body stores it at the end of every iteration), never from a value the lane
19
+ * loop is about to overwrite.
20
+ *
21
+ * A store loop is the same skeleton without an accumulator: the guard keeps
22
+ * the toggle and a whole vector and adds the entry tests the stored value
23
+ * needs, the lane loop transcribes the value's tree lane by lane and writes
24
+ * one vector, and the scalar copies write the elements the lanes left over.
25
+ *
26
+ * A dense `number[]` plan carries one more entry test. Its slots hold int32s
27
+ * or doubles, decided per array at run time and never mixed, so the guard
28
+ * also requires the storage kind the plan was made for (`SCR_ELEM_I32` for a
29
+ * sum's or count's exact integer elements, `SCR_ELEM_F64` for a store's
30
+ * doubles) and that every slot below the length holds a value (`filled`) —
31
+ * the scalar element read traps on a hole, and the lanes have nowhere to put
32
+ * that trap. A sum's or count's lanes read the int32 slots and widen them
33
+ * with their sign, which the entry bounds keep in range.
34
+ *
35
+ * Exactness. Each lane sums a subclass of the elements, and the lanes' i64
36
+ * sums are folded into the accumulator once. Any order gives the same double
37
+ * when every partial sum is an integer below 2^53 in magnitude. The plan
38
+ * requires the accumulator to be exactly +0 at the loop entry, so the loop's
39
+ * own partial sums are the sums of element prefixes, which the entry guard
40
+ * keeps below 2^53 for the sum shape (the count shape's result is at most the
41
+ * length). The scalar remainder then adds the elements the lanes left over:
42
+ * every partial sum of that addition is also a prefix sum of the loop, hence
43
+ * also below the bound. Node's ordered fadd chain over the same integers
44
+ * cannot round either, so both produce the same double. */
45
+ import { laneElem, laneShapesFromEnvironment, planLaneLoops } from "../../ir/lane-plans.js";
46
+ import { withinInt32 } from "../../ir/integer-ranges.js";
47
+ import { loadArrCount, SCR_ARR_FIELD } from "./common.js";
48
+ import { SCR_ELEM_F64, SCR_ELEM_I32 } from "./dense-array-access.js";
49
+ import { emitBytesData, emitBytesHeaderLength } from "./expr-bytes.js";
50
+ import { defineModuleState } from "./emitter-state.js";
51
+ /** The run-time toggle: `SCRIPTC_LANES=0` runs the scalar loops. */
52
+ const TOGGLE = "@sc_lanes";
53
+ /** The call main makes when the program has lane loops. */
54
+ export const LANE_INIT_CALL = ` call void @sc_lanes_init()`;
55
+ export const LANES = defineModuleState((emitter) => ({
56
+ shapes: laneShapesFromEnvironment(),
57
+ width: laneWidth(emitter),
58
+ plans: new Map(),
59
+ }));
60
+ /** Whether this build emits lane loops at all. */
61
+ export function lanePlansEnabled(emitter) {
62
+ return LANES.of(emitter).shapes.size > 0;
63
+ }
64
+ /** Integers per vector for the target. The width is a property of the
65
+ * target, not of a plan, so one plan lowers to every target's width. A
66
+ * target without vector integers (wasm) gets width 1 and no plans. */
67
+ export function laneWidth(emitter) {
68
+ if (emitter.wasi)
69
+ return 1;
70
+ const triple = emitter.targetTriple.toLowerCase();
71
+ const host = triple || `${process.arch}-${process.platform}`;
72
+ if (/^(aarch64|arm64)/.test(host))
73
+ return 4;
74
+ if (!/^(x86_64|amd64|x64)/.test(host))
75
+ return 1;
76
+ // A dispatching executable carries one body per level; the body is the
77
+ // baseline's width, which every level it runs on can execute.
78
+ if (emitter.cpuDispatch)
79
+ return 4;
80
+ switch (emitter.targetCpu) {
81
+ case "x86-64-v2":
82
+ return 4;
83
+ case "x86-64-v3":
84
+ return 8;
85
+ case "x86-64-v4":
86
+ return 16;
87
+ default:
88
+ return 4;
89
+ }
90
+ }
91
+ /** Sets the lane plans of the function emission is starting. The matcher is
92
+ * the loop matcher's: the function with its initializer bindings, which is
93
+ * the one `emitter.emitStmts` walks. */
94
+ export function beginFunctionLanes(emitter, fn) {
95
+ const state = LANES.of(emitter);
96
+ state.plans =
97
+ state.shapes.size === 0 || emitter.debug !== null
98
+ ? new Map()
99
+ : planLaneLoops(fn, emitter.numericLocals, state.shapes);
100
+ }
101
+ /** The plan for one loop, when the emitter can lower it here: a synchronous
102
+ * function on a target with vector integers, outside every value-layout copy
103
+ * the lane body does not write. */
104
+ export function laneLoopPlan(emitter, loop) {
105
+ const state = LANES.of(emitter);
106
+ if (state.width < 2 || emitter.debug !== null)
107
+ return null;
108
+ if (emitter.mod.workers === true || emitter.mod.bytesHeadersMutable === true)
109
+ return null;
110
+ if (emitter.speculation !== null || emitter.speculationResume !== null)
111
+ return null;
112
+ if (emitter.int32Kinds !== null)
113
+ return null;
114
+ const plan = state.plans.get(loop);
115
+ if (plan === undefined)
116
+ return null;
117
+ // The lane body stores the accumulator's double slot directly; an int32
118
+ // local keeps an integer in that slot, and its copies handle those loops.
119
+ if (plan.shape !== "store") {
120
+ if (emitter.int32Locals.has(plan.accumulator))
121
+ return null;
122
+ const binding = emitter.binding(plan.accumulator);
123
+ if (binding.kind !== "local" || binding.type.kind !== "f64")
124
+ return null;
125
+ }
126
+ return plan;
127
+ }
128
+ /** The LLVM integer comparison for a count's element test. */
129
+ const ICMP = new Map([
130
+ ["<", ["slt", "ult"]],
131
+ ["<=", ["sle", "ule"]],
132
+ [">", ["sgt", "ugt"]],
133
+ [">=", ["sge", "uge"]],
134
+ ["===", ["eq", "eq"]],
135
+ ["!==", ["ne", "ne"]],
136
+ ]);
137
+ /** The address of one %ScrArr header field. */
138
+ function arrayHeaderField(emitter, array, field) {
139
+ const B = emitter.B;
140
+ const ptr = B.tmp();
141
+ B.line(`${ptr} = getelementptr inbounds %ScrArr, ptr ${array}, i32 0, i32 ${field}`);
142
+ emitter.markMemoryPointer(ptr, "array:header");
143
+ return ptr;
144
+ }
145
+ /** A dense number array's length, or the hole-free prefix bound below which
146
+ * every slot holds a present value, in the target's size type. */
147
+ function emitArrayHeaderCount(emitter, array, field) {
148
+ const B = emitter.B;
149
+ const ptr = arrayHeaderField(emitter, array, SCR_ARR_FIELD[field]);
150
+ const count = B.tmp();
151
+ if (field === "len") {
152
+ loadArrCount(emitter, count, ptr, emitter.fieldAliasAttachment(ptr));
153
+ return count;
154
+ }
155
+ const narrow = B.tmp();
156
+ B.line(`${narrow} = load i32, ptr ${ptr}${emitter.fieldAliasAttachment(ptr)}`);
157
+ if (emitter.sizeType === "i32")
158
+ return narrow;
159
+ B.line(`${count} = zext i32 ${narrow} to i64`);
160
+ return count;
161
+ }
162
+ /** The dense value storage base of a number array. */
163
+ function emitArrayData(emitter, array) {
164
+ const B = emitter.B;
165
+ const ptr = arrayHeaderField(emitter, array, SCR_ARR_FIELD.data);
166
+ const data = B.tmp();
167
+ B.line(`${data} = load ptr, ptr ${ptr}${emitter.fieldAliasAttachment(ptr)}`);
168
+ return data;
169
+ }
170
+ /** Whether every slot below the array's length is a present value held in
171
+ * the storage the plan reads: `length <= filled`, and the array's slots are
172
+ * the kind the plan was made for. A dense array keeps every slot below
173
+ * `filled` a present value, so the lane loop needs no per-element state
174
+ * test; the storage kind decides whether those slots are int32s (sums and
175
+ * counts) or doubles (stores). */
176
+ function emitDenseSlotTest(emitter, array, length, elem) {
177
+ const B = emitter.B;
178
+ const size = emitter.sizeType;
179
+ const filled = emitArrayHeaderCount(emitter, array, "filled");
180
+ const covered = B.tmp();
181
+ B.line(`${covered} = icmp ule ${size} ${length}, ${filled}`);
182
+ const kindPtr = arrayHeaderField(emitter, array, SCR_ARR_FIELD.elem);
183
+ const kind = B.tmp(), same = B.tmp(), wanted = elem === "i32slot" ? SCR_ELEM_I32 : SCR_ELEM_F64;
184
+ B.line(`${kind} = load i8, ptr ${kindPtr}${emitter.fieldAliasAttachment(kindPtr)}`);
185
+ B.line(`${same} = icmp eq i8 ${kind}, ${wanted}`);
186
+ const ok = B.tmp();
187
+ B.line(`${ok} = and i1 ${covered}, ${same}`);
188
+ return ok;
189
+ }
190
+ function emitLaneEntry(emitter, plan, receiver, inductionSlot) {
191
+ const B = emitter.B;
192
+ const width = LANES.of(emitter).width;
193
+ const size = emitter.sizeType;
194
+ const view = emitter.emitStableReceiver(receiver, []);
195
+ const length = plan.container === "bytes"
196
+ ? emitBytesHeaderLength(emitter, view.name)
197
+ : emitArrayHeaderCount(emitter, view.name, "len");
198
+ const data = plan.container === "bytes"
199
+ ? emitBytesData(emitter, view.name)
200
+ : emitArrayData(emitter, view.name);
201
+ const storage = plan.container === "bytes" ? null : emitDenseSlotTest(emitter, view.name, length, plan.elem);
202
+ // The counter at the entry, and the elements left from it: the lane loop
203
+ // covers the whole vectors of that span and leaves the rest to the loop.
204
+ const start = B.tmp(), span = B.tmp();
205
+ B.line(`${start} = load ${size}, ptr ${inductionSlot}`);
206
+ B.line(`${span} = sub nuw ${size} ${length}, ${start}`);
207
+ // The toggle: a predictable load every entry, as the design's guard says.
208
+ const toggle = B.tmp(), enabled = B.tmp(), wide = B.tmp();
209
+ B.line(`${toggle} = load i32, ptr ${TOGGLE}`);
210
+ B.line(`${enabled} = icmp ne i32 ${toggle}, 0`);
211
+ B.line(`${wide} = icmp uge ${size} ${span}, ${width}`);
212
+ const entry = {
213
+ length,
214
+ data,
215
+ start,
216
+ span,
217
+ whole: "",
218
+ limit: "",
219
+ ok: "",
220
+ base: "",
221
+ tighten: (cond) => {
222
+ const both = B.tmp();
223
+ B.line(`${both} = and i1 ${entry.ok}, ${cond}`);
224
+ entry.ok = both;
225
+ },
226
+ };
227
+ let first = B.tmp();
228
+ B.line(`${first} = and i1 ${enabled}, ${wide}`);
229
+ if (storage !== null) {
230
+ const inStorage = B.tmp();
231
+ B.line(`${inStorage} = and i1 ${first}, ${storage}`);
232
+ first = inStorage;
233
+ }
234
+ entry.ok = first;
235
+ entry.base = first;
236
+ // The lane loop's exclusive end: whole vectors from the entry.
237
+ const whole = B.tmp(), limit = B.tmp();
238
+ B.line(`${whole} = and ${size} ${span}, ${-width}`);
239
+ B.line(`${limit} = add nuw ${size} ${start}, ${whole}`);
240
+ entry.whole = whole;
241
+ entry.limit = limit;
242
+ return entry;
243
+ }
244
+ /** Emits the entry guard and the lane loop for `plan`, then starts `cont`.
245
+ * `receiver` is the loop's limit expression (the typed array read at the
246
+ * induction variable); `inductionSlot` is the loop's counter. Every path out
247
+ * of the lane code reaches `cont` with the scalar loop's inputs in place: the
248
+ * counter at the lane loop's limit when the lanes ran, untouched when they
249
+ * did not. */
250
+ export function emitLaneLoop(emitter, plan, receiver, inductionSlot, cont) {
251
+ if (plan.shape === "store") {
252
+ emitLaneStore(emitter, plan, receiver, inductionSlot, cont);
253
+ return;
254
+ }
255
+ const B = emitter.B;
256
+ const width = LANES.of(emitter).width;
257
+ const elem = laneElem(plan.elem);
258
+ if (elem === null)
259
+ throw new Error(`lane plan on a ${plan.elem} element`);
260
+ const size = emitter.sizeType;
261
+ const entry = emitLaneEntry(emitter, plan, receiver, inductionSlot);
262
+ const { length, data, limit } = entry;
263
+ if (plan.shape === "sum") {
264
+ const bound = B.tmp();
265
+ B.line(`${bound} = icmp ult ${size} ${length}, ${plan.lengthBound}`);
266
+ entry.tighten(bound);
267
+ }
268
+ const init = B.newLabel("lane.init"), header = B.newLabel("lane.c"), body = B.newLabel("lane.b"), exit = B.newLabel("lane.x");
269
+ const accSlot = B.slot();
270
+ B.entryAllocas.push(`${accSlot} = alloca <${width} x i64> ; lane sums`);
271
+ let record = `<${width} x i64> zeroinitializer`;
272
+ if (plan.shape === "count") {
273
+ // `element <op> limit` in integers: the limit must be an exact integer
274
+ // in the element's range, which the entry checks once. Otherwise the
275
+ // scalar loop answers with the same doubles it would have compared.
276
+ const value = emitter.emitExpr(plan.compare.limit);
277
+ const lowest = elem.signed ? -(2 ** (elem.bits - 1)) : 0;
278
+ const highest = elem.signed ? 2 ** (elem.bits - 1) : 2 ** elem.bits;
279
+ const lowOk = B.tmp(), highOk = B.tmp(), inRange = B.tmp(), safe = B.tmp();
280
+ B.line(`${lowOk} = fcmp oge double ${value.name}, ${lowest}.0`);
281
+ B.line(`${highOk} = fcmp olt double ${value.name}, ${highest}.0`);
282
+ B.line(`${inRange} = and i1 ${lowOk}, ${highOk}`);
283
+ B.line(`${safe} = select i1 ${inRange}, double ${value.name}, double 0.0`);
284
+ const narrow64 = B.tmp(), back = B.tmp(), exact = B.tmp();
285
+ B.line(`${narrow64} = fptosi double ${safe} to i64`);
286
+ B.line(`${back} = sitofp i64 ${narrow64} to double`);
287
+ B.line(`${exact} = fcmp oeq double ${back}, ${value.name}`);
288
+ const integer = B.tmp();
289
+ B.line(`${integer} = and i1 ${inRange}, ${exact}`);
290
+ entry.tighten(integer);
291
+ const narrow = B.tmp(), first = B.tmp(), splat = B.tmp();
292
+ B.line(`${narrow} = trunc i64 ${narrow64} to ${elem.type}`);
293
+ B.line(`${first} = insertelement <${width} x ${elem.type}> poison, ${elem.type} ${narrow}, i32 0`);
294
+ B.line(`${splat} = shufflevector <${width} x ${elem.type}> ${first}, <${width} x ${elem.type}> poison, <${width} x i32> zeroinitializer`);
295
+ record = splat;
296
+ }
297
+ B.condBr(entry.ok, init, cont);
298
+ B.startBlock(init);
299
+ B.line(`store <${width} x i64> zeroinitializer, ptr ${accSlot}`);
300
+ B.br(header);
301
+ B.startBlock(header);
302
+ const index = B.tmp(), more = B.tmp();
303
+ B.line(`${index} = load ${size}, ptr ${inductionSlot}`);
304
+ B.line(`${more} = icmp ult ${size} ${index}, ${limit}`);
305
+ B.condBr(more, body, exit);
306
+ B.startBlock(body);
307
+ const at = B.tmp(), elements = B.tmp(), terms = B.tmp(), before = B.tmp(), after = B.tmp(), next = B.tmp();
308
+ B.line(`${at} = getelementptr inbounds ${elem.type}, ptr ${data}, ${size} ${index}`);
309
+ // align 1: a view's backing may be any alignment; the load still lowers to
310
+ // one unaligned vector move on every target this emits for.
311
+ B.line(`${elements} = load <${width} x ${elem.type}>, ptr ${at}, align 1`);
312
+ if (plan.shape === "sum") {
313
+ B.line(`${terms} = ${elem.signed ? "sext" : "zext"} <${width} x ${elem.type}> ${elements} to <${width} x i64>`);
314
+ }
315
+ else {
316
+ const [signed, unsigned] = ICMP.get(plan.compare.op) ?? ["sge", "uge"];
317
+ const mask = B.tmp();
318
+ B.line(`${mask} = icmp ${elem.signed ? signed : unsigned} <${width} x ${elem.type}> ${elements}, ${record}`);
319
+ B.line(`${terms} = zext <${width} x i1> ${mask} to <${width} x i64>`);
320
+ }
321
+ B.line(`${before} = load <${width} x i64>, ptr ${accSlot}`);
322
+ B.line(`${after} = add <${width} x i64> ${before}, ${terms}`);
323
+ B.line(`store <${width} x i64> ${after}, ptr ${accSlot}`);
324
+ B.line(`${next} = add nuw ${size} ${index}, ${width}`);
325
+ B.line(`store ${size} ${next}, ptr ${inductionSlot}`);
326
+ B.br(header);
327
+ B.startBlock(exit);
328
+ const lanes = B.tmp();
329
+ B.line(`${lanes} = load <${width} x i64>, ptr ${accSlot}`);
330
+ let reduced = null;
331
+ for (let lane = 0; lane < width; lane++) {
332
+ const value = B.tmp();
333
+ B.line(`${value} = extractelement <${width} x i64> ${lanes}, i32 ${lane}`);
334
+ if (reduced === null)
335
+ reduced = value;
336
+ else {
337
+ const sum = B.tmp();
338
+ B.line(`${sum} = add i64 ${reduced}, ${value}`);
339
+ reduced = sum;
340
+ }
341
+ }
342
+ const exact = B.tmp(), current = B.tmp(), total = B.tmp();
343
+ B.line(`${exact} = sitofp i64 ${reduced} to double`);
344
+ B.line(`${current} = load double, ptr ${emitter.binding(plan.accumulator).slot}`);
345
+ B.line(`${total} = fadd double ${current}, ${exact}`);
346
+ B.line(`store double ${total}, ptr ${emitter.binding(plan.accumulator).slot}`);
347
+ B.br(cont);
348
+ B.startBlock(cont);
349
+ }
350
+ function storeElem(elem) {
351
+ switch (elem) {
352
+ case "u8c":
353
+ return { type: "i8", max: 255, float: false, clamped: true, signed: false };
354
+ case "u8":
355
+ return { type: "i8", max: 255, float: false, clamped: false, signed: false };
356
+ case "i8":
357
+ return { type: "i8", max: 128, float: false, clamped: false, signed: true };
358
+ case "u16":
359
+ return { type: "i16", max: 65535, float: false, clamped: false, signed: false };
360
+ case "i16":
361
+ return { type: "i16", max: 32768, float: false, clamped: false, signed: true };
362
+ case "u32":
363
+ return { type: "i32", max: 4294967295, float: false, clamped: false, signed: false };
364
+ case "i32":
365
+ return { type: "i32", max: 2147483648, float: false, clamped: false, signed: true };
366
+ case "f32":
367
+ return { type: "float", max: 0, float: true, clamped: false, signed: true };
368
+ case "f64":
369
+ return { type: "double", max: 0, float: true, clamped: false, signed: true };
370
+ // A dense number array's double slots hold the stored double as it is.
371
+ case "f64slot":
372
+ return { type: "double", max: 0, float: true, clamped: false, signed: true };
373
+ default:
374
+ return null;
375
+ }
376
+ }
377
+ /** A vector holding one constant in every lane, as the constant expression
378
+ * the IR uses (`splat (i64 1)`). */
379
+ function vectorSplatLiteral(type, literal) {
380
+ return `splat (${type} ${literal})`;
381
+ }
382
+ /** `<W x i64>` <0, 1, ... W-1>, built once per loop entry: the constant
383
+ * folding pass turns the chain into a vector constant. */
384
+ function laneIndices(emitter, width) {
385
+ const B = emitter.B;
386
+ let vec = B.tmp();
387
+ B.line(`${vec} = insertelement <${width} x i64> poison, i64 0, i32 0`);
388
+ for (let lane = 1; lane < width; lane++) {
389
+ const next = B.tmp();
390
+ B.line(`${next} = insertelement <${width} x i64> ${vec}, i64 ${lane}, i32 ${lane}`);
391
+ vec = next;
392
+ }
393
+ return vec;
394
+ }
395
+ function splatValue(emitter, type, value, width) {
396
+ const B = emitter.B;
397
+ const first = B.tmp(), vec = B.tmp();
398
+ B.line(`${first} = insertelement <${width} x ${type}> poison, ${type} ${value}, i32 0`);
399
+ B.line(`${vec} = shufflevector <${width} x ${type}> ${first}, <${width} x ${type}> poison, <${width} x i32> zeroinitializer`);
400
+ return vec;
401
+ }
402
+ /** An exact integer a stored value's invariant contributes, when it has one:
403
+ * the integer the invariant was emitted with, or an integer literal within
404
+ * int32. The literal's bound is what keeps the integer route's i64 arithmetic
405
+ * from overflowing: an induction below 2^31 times such a literal is below
406
+ * 2^62. A larger or fractional literal takes the double route instead. */
407
+ function invariantInteger(expr, value) {
408
+ if (value.integer !== undefined)
409
+ return value.integer;
410
+ if (expr.kind !== "numLit")
411
+ return null;
412
+ const literal = expr.value;
413
+ if (!Number.isInteger(literal) || Object.is(literal, -0))
414
+ return null;
415
+ if (!withinInt32({ min: literal, max: literal }))
416
+ return null;
417
+ return { type: "i64", name: String(literal), range: { min: literal, max: literal } };
418
+ }
419
+ /** The value's low 32 bits as lanes: ToUint32, exactly as expr-bytes.ts
420
+ * `emitToUint32` computes it. `emitValueBound` keeps every lane below 2^63 in
421
+ * magnitude at the loop entry, where one `fptosi` and one `trunc` are the
422
+ * integer the scalar body's own fast path stores. */
423
+ function emitVectorToUint32(emitter, value, width) {
424
+ const B = emitter.B;
425
+ const integer = B.tmp(), low = B.tmp();
426
+ B.line(`${integer} = fptosi <${width} x double> ${value} to <${width} x i64>`);
427
+ B.line(`${low} = trunc <${width} x i64> ${integer} to <${width} x i32>`);
428
+ return low;
429
+ }
430
+ /** ToUint8Clamp as one lane of a vector, the same branch-free form the
431
+ * scalar store uses: NaN and values at most 0 store 0, values at least 255
432
+ * store 255, and the others round to nearest with ties to even. */
433
+ function emitVectorClamp(emitter, value, width) {
434
+ const B = emitter.B;
435
+ const v = `<${width} x double>`;
436
+ const positive = B.tmp(), high = B.tmp(), shifted = B.tmp(), rounded = B.tmp(), upper = B.tmp(), clamped = B.tmp();
437
+ B.line(`${positive} = fcmp ogt ${v} ${value}, ${vectorSplatLiteral("double", "0.0")}`);
438
+ B.line(`${high} = fcmp oge ${v} ${value}, ${vectorSplatLiteral("double", "255.0")}`);
439
+ B.line(`${shifted} = fadd ${v} ${value}, ${vectorSplatLiteral("double", "4503599627370496.0")}`);
440
+ B.line(`${rounded} = fsub ${v} ${shifted}, ${vectorSplatLiteral("double", "4503599627370496.0")}`);
441
+ B.line(`${upper} = select <${width} x i1> ${high}, ${v} ${vectorSplatLiteral("double", "255.0")}, ${v} ${rounded}`);
442
+ B.line(`${clamped} = select <${width} x i1> ${positive}, ${v} ${upper}, ${v} zeroinitializer`);
443
+ const out = B.tmp();
444
+ B.line(`${out} = fptoui ${v} ${clamped} to <${width} x i32>`);
445
+ return out;
446
+ }
447
+ function once(emit) {
448
+ let value = null;
449
+ return () => (value ??= emit());
450
+ }
451
+ /** An exact integer as `<W x i64>` lanes. An i32 integer widens with its sign,
452
+ * which the element store never sees past the low bits and the entry bounds
453
+ * keep in range; i64 integers are already lanes. */
454
+ function integerLanes(emitter, integer, width) {
455
+ const lanes = splatValue(emitter, integer.type, integer.name, width);
456
+ if (integer.type === "i64")
457
+ return lanes;
458
+ const wide = emitter.B.tmp();
459
+ emitter.B.line(`${wide} = sext <${width} x i32> ${lanes} to <${width} x i64>`);
460
+ return wide;
461
+ }
462
+ /** One node of the stored value as lanes: the scalar loop's operations,
463
+ * applied to `<W x double>` or `<W x i64>` instead of doubles and integers. */
464
+ function laneNodeValue(emitter, node, ctx) {
465
+ const B = emitter.B;
466
+ const { width } = ctx;
467
+ if (node.op === null) {
468
+ if (node.role === "induction")
469
+ return { int: ctx.integers ? ctx.index : null, dbl: ctx.indexDouble };
470
+ if (node.role === "element")
471
+ return { int: null, dbl: once(() => emitElementLanes(emitter, ctx)) };
472
+ const value = ctx.invariants.get(node.expr);
473
+ const integer = ctx.integers ? invariantInteger(node.expr, value) : null;
474
+ return {
475
+ int: integer === null ? null : integerLanes(emitter, integer, width),
476
+ dbl: once(() => splatValue(emitter, "double", value.name, width)),
477
+ };
478
+ }
479
+ const left = laneNodeValue(emitter, node.left, ctx);
480
+ const right = laneNodeValue(emitter, node.right, ctx);
481
+ if (node.op === "*") {
482
+ // The double form is what a float element stores. An integer element
483
+ // stores the exact product when both operands are exact integers: the
484
+ // entry bound keeps it below 2^62, inside i64.
485
+ let product = null;
486
+ if (left.int !== null && right.int !== null) {
487
+ product = B.tmp();
488
+ B.line(`${product} = mul nsw <${width} x i64> ${left.int}, ${right.int}`);
489
+ }
490
+ return {
491
+ int: product,
492
+ dbl: once(() => {
493
+ const value = B.tmp();
494
+ B.line(`${value} = fmul <${width} x double> ${left.dbl()}, ${right.dbl()}`);
495
+ return value;
496
+ }),
497
+ };
498
+ }
499
+ if (left.int !== null && right.int !== null) {
500
+ const result = B.tmp();
501
+ B.line(`${result} = ${node.op === "+" ? "add" : "sub"} nsw <${width} x i64> ${left.int}, ${right.int}`);
502
+ return {
503
+ int: result,
504
+ dbl: once(() => {
505
+ const exact = B.tmp();
506
+ B.line(`${exact} = sitofp <${width} x i64> ${result} to <${width} x double>`);
507
+ return exact;
508
+ }),
509
+ };
510
+ }
511
+ const result = B.tmp();
512
+ B.line(`${result} = ${node.op === "+" ? "fadd" : "fsub"} <${width} x double> ${left.dbl()}, ${right.dbl()}`);
513
+ return { int: null, dbl: () => result };
514
+ }
515
+ /** `receiver[induction]` as `<W x double>`, through the element conversion
516
+ * the scalar read uses (widen to i32, then convert to double). */
517
+ function emitElementLanes(emitter, ctx) {
518
+ const B = emitter.B;
519
+ const { width, data } = ctx;
520
+ const info = storeElem(ctx.elem);
521
+ const at = B.tmp(), raw = B.tmp();
522
+ B.line(`${at} = getelementptr inbounds ${info.type}, ptr ${data}, ${emitter.sizeType} ${ctx.scalar}`);
523
+ B.line(`${raw} = load <${width} x ${info.type}>, ptr ${at}, align 1`);
524
+ if (info.type === "double")
525
+ return raw;
526
+ if (info.type === "float") {
527
+ const wide = B.tmp();
528
+ B.line(`${wide} = fpext <${width} x float> ${raw} to <${width} x double>`);
529
+ return wide;
530
+ }
531
+ const wide = info.type === "i32" ? raw : B.tmp();
532
+ if (info.type !== "i32")
533
+ B.line(`${wide} = ${info.signed ? "sext" : "zext"} <${width} x ${info.type}> ${raw} to <${width} x i32>`);
534
+ const out = B.tmp();
535
+ B.line(`${out} = ${info.signed ? "sitofp" : "uitofp"} <${width} x i32> ${wide} to <${width} x double>`);
536
+ return out;
537
+ }
538
+ /** Every invariant expression in a stored value. */
539
+ function storeInvariants(node, out) {
540
+ if (node.left !== null)
541
+ storeInvariants(node.left, out);
542
+ if (node.right !== null)
543
+ storeInvariants(node.right, out);
544
+ if (node.role === "invariant" && node.expr !== null)
545
+ out.push(node.expr);
546
+ }
547
+ /** Whether a stored value reads the element or the induction. */
548
+ function storeReads(node, role) {
549
+ if (node.role === role)
550
+ return true;
551
+ return ((node.left !== null && storeReads(node.left, role)) ||
552
+ (node.right !== null && storeReads(node.right, role)));
553
+ }
554
+ /** A scalar double that no lane of the stored value exceeds in magnitude,
555
+ * computed with each operand at its own largest: the element at the widest
556
+ * value its type holds, an invariant at its magnitude, the counter at the
557
+ * array's length. Every operation is monotone and the lanes apply the same
558
+ * operations to smaller operands, so rounding the bound can only overstate
559
+ * the lanes. A NaN anywhere leaves the bound a NaN, which fails the test. */
560
+ function emitValueBound(emitter, node, invariants, elementMax, length) {
561
+ const B = emitter.B;
562
+ if (node.op === null) {
563
+ if (node.role === "induction") {
564
+ const count = B.tmp();
565
+ B.line(`${count} = uitofp ${emitter.sizeType} ${length} to double`);
566
+ return count;
567
+ }
568
+ if (node.role === "element")
569
+ return `${elementMax}.0`;
570
+ const value = invariants.get(node.expr);
571
+ const positive = B.tmp(), negative = B.tmp(), magnitude = B.tmp();
572
+ B.line(`${positive} = fcmp oge double ${value.name}, 0.0`);
573
+ B.line(`${negative} = fneg double ${value.name}`);
574
+ B.line(`${magnitude} = select i1 ${positive}, double ${value.name}, double ${negative}`);
575
+ return magnitude;
576
+ }
577
+ const left = emitValueBound(emitter, node.left, invariants, elementMax, length);
578
+ const right = emitValueBound(emitter, node.right, invariants, elementMax, length);
579
+ const combined = B.tmp();
580
+ B.line(`${combined} = ${node.op === "*" ? "fmul" : "fadd"} double ${left}, ${right}`);
581
+ return combined;
582
+ }
583
+ /** Emits a store loop for `plan`: whole vectors of the array are written
584
+ * from lane values, and the loop's own copies write what the lanes left.
585
+ *
586
+ * Every lane computes the value with the operations the scalar body uses,
587
+ * on the same operands, so the stored bits are the scalar loop's. Entry
588
+ * tests keep that true where the lanes take a different route than the
589
+ * scalar body: the exact integer the integer lanes compute must stay below
590
+ * 2^53 in magnitude, an element times an exact integer must keep every
591
+ * product it meets exact, and a value converted straight to ToUint32 must
592
+ * stay below 2^63. All are loop-invariant, so the scalar remainder still
593
+ * answers with its own bytes whenever they fail. */
594
+ function emitLaneStore(emitter, plan, receiver, inductionSlot, cont) {
595
+ const B = emitter.B;
596
+ const width = LANES.of(emitter).width;
597
+ const info = storeElem(plan.elem);
598
+ if (info === null)
599
+ throw new Error(`lane store on a ${plan.elem} element`);
600
+ const invariants = new Map();
601
+ const exprs = [];
602
+ storeInvariants(plan.value, exprs);
603
+ for (const expr of exprs)
604
+ if (!invariants.has(expr))
605
+ invariants.set(expr, emitter.emitExpr(expr));
606
+ const exact = [...invariants.entries()].flatMap(([expr, value]) => {
607
+ const integer = invariantInteger(expr, value);
608
+ return integer === null ? [] : [{ name: value.name, integer }];
609
+ });
610
+ const usesElement = storeReads(plan.value, "element");
611
+ const size = emitter.sizeType;
612
+ // Entry tests beyond the shared guard, each a loop-invariant condition on
613
+ // the values the scalar body is about to read.
614
+ const tests = [];
615
+ const magnitude = (name, range, limit) => {
616
+ if (range.min > -limit && range.max < limit)
617
+ return;
618
+ tests.push((entry) => {
619
+ const low = B.tmp(), high = B.tmp();
620
+ B.line(`${low} = fcmp ogt double ${name}, ${-limit}.0`);
621
+ B.line(`${high} = fcmp olt double ${name}, ${limit}.0`);
622
+ entry.tighten(low);
623
+ entry.tighten(high);
624
+ });
625
+ };
626
+ // An integer element is stored from the exact integer the scalar body
627
+ // computes when every operand is an exact integer; the value is then
628
+ // ToUint32's low bits, which the integer route truncates directly. A
629
+ // float element is always stored from the scalar body's own doubles: the
630
+ // lane body applies the same operations to the same operands, so its
631
+ // result is bit-identical and needs no test.
632
+ let int = false;
633
+ if (!info.float) {
634
+ if (!usesElement && exact.length === invariants.size) {
635
+ // The integer route stores the low bits of the exact integer its lane
636
+ // arithmetic produces. Those are the scalar body's bytes only while
637
+ // the value stays below 2^53 in magnitude: below it every integer is
638
+ // its own double, so the scalar body's double form stores the same
639
+ // bits, and above it the double rounds and its low bits differ. A
640
+ // clamped element rounds and clamps the double, so it needs no test.
641
+ int = true;
642
+ if (!info.clamped)
643
+ tests.push((entry) => {
644
+ const limit = emitValueBound(emitter, plan.value, invariants, info.max, entry.length);
645
+ const within = B.tmp();
646
+ B.line(`${within} = fcmp olt double ${limit}, 9007199254740992.0`);
647
+ entry.tighten(within);
648
+ });
649
+ }
650
+ else if (exact.length > 0 && usesElement) {
651
+ // An element operand and an exact integer in one operation: the scalar
652
+ // body may have done the operation on the integers. Below 2^53 the
653
+ // double form stores the same bits.
654
+ const limit = Math.floor(plan.value.op === "*" ? 2 ** 53 / info.max : 2 ** 53 - info.max);
655
+ for (const value of exact)
656
+ magnitude(value.name, value.integer.range, limit);
657
+ }
658
+ if (!int && !info.clamped) {
659
+ // The lanes that are not exact integers take ToUint32's direct
660
+ // conversion, which is exact below 2^63. The entry test asks whether
661
+ // the value's own magnitude, with every operand at its largest, stays
662
+ // there; loops that can leave it keep their scalar form.
663
+ tests.push((entry) => {
664
+ const limit = emitValueBound(emitter, plan.value, invariants, info.max, entry.length);
665
+ const inside = B.tmp();
666
+ B.line(`${inside} = fcmp olt double ${limit}, 9223372036854775808.0`);
667
+ entry.tighten(inside);
668
+ });
669
+ }
670
+ }
671
+ const entry = emitLaneEntry(emitter, plan, receiver, inductionSlot);
672
+ const steps = laneIndices(emitter, width);
673
+ const header = B.newLabel("lane.c"), body = B.newLabel("lane.b"), exit = B.newLabel("lane.x");
674
+ // The shape's own tests are computed only where the shared guard holds, so
675
+ // a build with the toggle off pays the toggle load and the guard's branch,
676
+ // not the bounds, for every loop it keeps scalar.
677
+ if (tests.length === 0)
678
+ B.condBr(entry.ok, header, cont);
679
+ else {
680
+ const test = B.newLabel("lane.t");
681
+ B.condBr(entry.base, test, cont);
682
+ B.startBlock(test);
683
+ for (const run of tests)
684
+ run(entry);
685
+ B.condBr(entry.ok, header, cont);
686
+ }
687
+ B.startBlock(header);
688
+ const index = B.tmp(), more = B.tmp();
689
+ B.line(`${index} = load ${size}, ptr ${inductionSlot}`);
690
+ B.line(`${more} = icmp ult ${size} ${index}, ${entry.limit}`);
691
+ B.condBr(more, body, exit);
692
+ B.startBlock(body);
693
+ const indices = B.tmp();
694
+ B.line(`${indices} = add <${width} x i64> ${steps}, ${splatValue(emitter, "i64", index, width)}`);
695
+ const ctx = {
696
+ width,
697
+ data: entry.data,
698
+ elem: plan.elem,
699
+ scalar: index,
700
+ index: indices,
701
+ indexDouble: once(() => {
702
+ const doubles = B.tmp();
703
+ B.line(`${doubles} = sitofp <${width} x i64> ${indices} to <${width} x double>`);
704
+ return doubles;
705
+ }),
706
+ invariants,
707
+ integers: !info.float,
708
+ };
709
+ const value = laneNodeValue(emitter, plan.value, ctx);
710
+ const at = B.tmp();
711
+ B.line(`${at} = getelementptr inbounds ${info.type}, ptr ${entry.data}, ${size} ${index}`);
712
+ const type = info.type;
713
+ const exactInteger = int ? value.int : null;
714
+ let stored;
715
+ if (info.float) {
716
+ const doubles = value.dbl();
717
+ if (type === "float") {
718
+ stored = B.tmp();
719
+ B.line(`${stored} = fptrunc <${width} x double> ${doubles} to <${width} x float>`);
720
+ }
721
+ else
722
+ stored = doubles;
723
+ }
724
+ else if (info.clamped) {
725
+ // Rounding and clamping are the scalar body's own double operations.
726
+ const bits = emitVectorClamp(emitter, value.dbl(), width);
727
+ stored = B.tmp();
728
+ B.line(`${stored} = trunc <${width} x i32> ${bits} to <${width} x i8>`);
729
+ }
730
+ else {
731
+ // Every element type is at most 32 bits wide, so the value is ToUint32
732
+ // of the scalar body's number, as emitBytesSet stores it.
733
+ const from = exactInteger === null ? "i32" : "i64";
734
+ const bits = exactInteger === null ? emitVectorToUint32(emitter, value.dbl(), width) : exactInteger;
735
+ if (type === from)
736
+ stored = bits;
737
+ else {
738
+ stored = B.tmp();
739
+ B.line(`${stored} = trunc <${width} x ${from}> ${bits} to <${width} x ${type}>`);
740
+ }
741
+ }
742
+ B.line(`store <${width} x ${type}> ${stored}, ptr ${at}, align 1`);
743
+ const next = B.tmp();
744
+ B.line(`${next} = add nuw ${size} ${index}, ${width}`);
745
+ B.line(`store ${size} ${next}, ptr ${inductionSlot}`);
746
+ B.br(header);
747
+ B.startBlock(exit);
748
+ B.br(cont);
749
+ B.startBlock(cont);
750
+ }
751
+ /** @sc_lanes and @sc_lanes_init, which main calls first: `SCRIPTC_LANES=0`
752
+ * turns every lane loop off, and any other value leaves them on. */
753
+ export function laneToggleDefs(declare) {
754
+ declare(`declare ptr @getenv(ptr)`);
755
+ declare(`declare i32 @strcmp(ptr, ptr)`);
756
+ return [
757
+ `${TOGGLE} = internal global i32 1`,
758
+ `@sc_lanes_env = private unnamed_addr constant [14 x i8] c"SCRIPTC_LANES\\00"`,
759
+ `@sc_lanes_off = private unnamed_addr constant [2 x i8] c"0\\00"`,
760
+ `define internal void @sc_lanes_init() #0 {`,
761
+ `entry:`,
762
+ ` %env = call ptr @getenv(ptr @sc_lanes_env)`,
763
+ ` %has = icmp ne ptr %env, null`,
764
+ ` br i1 %has, label %check, label %done`,
765
+ `check:`,
766
+ ` %same = call i32 @strcmp(ptr %env, ptr @sc_lanes_off)`,
767
+ ` %off = icmp eq i32 %same, 0`,
768
+ ` br i1 %off, label %disable, label %done`,
769
+ `disable:`,
770
+ ` store i32 0, ptr ${TOGGLE}`,
771
+ ` br label %done`,
772
+ `done:`,
773
+ ` ret void`,
774
+ `}`,
775
+ ``,
776
+ ];
777
+ }
778
+ //# sourceMappingURL=lanes.js.map