@onda-lang/wasm-compiler 0.8.0 → 0.8.2
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.
- package/README.md +6 -0
- package/THIRD_PARTY_NOTICES.md +4 -2
- package/dist/backend/compiler/core.js +2544 -0
- package/dist/backend/compiler/index.js +1900 -0
- package/dist/backend/compiler/lowering.js +2297 -0
- package/dist/backend/compiler/shared.js +247 -0
- package/dist/backend/index.js +1 -6903
- package/dist/build.json +3 -3
- package/dist/frontend/onda_compiler_web_bg.wasm +0 -0
- package/dist/frontend/package.json +2 -2
- package/dist/licenses/ONDA-LICENSE.txt +21 -0
- package/dist/licenses/RUST-DEPENDENCIES.txt +953 -0
- package/dist/version.js +1 -1
- package/package.json +2 -2
- /package/dist/licenses/{BINARYEN-LICENSE → BINARYEN-LICENSE.txt} +0 -0
- /package/dist/licenses/{LIBM-LICENSE → LIBM-LICENSE.txt} +0 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import binaryen from "binaryen";
|
|
2
|
+
import { SUPPORTED_MIR_SCHEMA_VERSION } from "../constants.js";
|
|
3
|
+
import { OndaBinaryenError } from "../errors.js";
|
|
4
|
+
import { supportsMirOperation } from "../operations.js";
|
|
5
|
+
import { ONDA_MATH_KERNEL_WASM } from "../math-kernel.generated.js";
|
|
6
|
+
import {
|
|
7
|
+
PROCESSOR_ABI_VERSION,
|
|
8
|
+
PROCESSOR_ARTIFACT_FORMAT,
|
|
9
|
+
PROCESSOR_ARTIFACT_FORMAT_VERSION,
|
|
10
|
+
PROCESSOR_EXECUTION_OK,
|
|
11
|
+
PROCESSOR_EXECUTION_RUNTIME_SAFETY_FAILURE,
|
|
12
|
+
PROCESSOR_SNAPSHOT_FORMAT_VERSION,
|
|
13
|
+
validateProcessorMetadata,
|
|
14
|
+
} from "../artifact.js";
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
SUPPORTED_MIR_SCHEMA_VERSION,
|
|
18
|
+
OndaBinaryenError,
|
|
19
|
+
supportsMirOperation,
|
|
20
|
+
ONDA_MATH_KERNEL_WASM,
|
|
21
|
+
PROCESSOR_ABI_VERSION,
|
|
22
|
+
PROCESSOR_ARTIFACT_FORMAT,
|
|
23
|
+
PROCESSOR_ARTIFACT_FORMAT_VERSION,
|
|
24
|
+
PROCESSOR_EXECUTION_OK,
|
|
25
|
+
PROCESSOR_EXECUTION_RUNTIME_SAFETY_FAILURE,
|
|
26
|
+
PROCESSOR_SNAPSHOT_FORMAT_VERSION,
|
|
27
|
+
validateProcessorMetadata,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const PAGE_BYTES = 64 * 1024;
|
|
31
|
+
export const STATIC_BASE = 1024;
|
|
32
|
+
export const MATH_KERNEL_RESERVED_END = 32 * 1024;
|
|
33
|
+
export const MATH_KERNEL_DATA_SEGMENT = ".rodata";
|
|
34
|
+
export const MATH_KERNEL_STACK_GLOBAL = "__stack_pointer";
|
|
35
|
+
export const MAX_MEMORY_PAGES = 65_536;
|
|
36
|
+
export const WASM32_ADDRESS_SPACE_BYTES = MAX_MEMORY_PAGES * PAGE_BYTES;
|
|
37
|
+
export const DEFAULT_OPTIMIZE_LEVEL = 4;
|
|
38
|
+
export const ONDA_PROCESS_FULL_BLOCK = (1 << 0) | (1 << 1);
|
|
39
|
+
export const DELEGATE_RECORD_HEADER_SIZE = 12;
|
|
40
|
+
export const DELEGATE_BATCH_STORAGE_OFFSET = 0;
|
|
41
|
+
export const DELEGATE_BATCH_CAPACITY_OFFSET = 4;
|
|
42
|
+
export const DELEGATE_BATCH_USED_OFFSET = 8;
|
|
43
|
+
export const DELEGATE_BATCH_RECORD_COUNT_OFFSET = 12;
|
|
44
|
+
export const DELEGATE_BATCH_OVERFLOW_OFFSET = 16;
|
|
45
|
+
export const PRINT_RECORD_HEADER_SIZE = 12;
|
|
46
|
+
export const PRINT_BATCH_STORAGE_OFFSET = 0;
|
|
47
|
+
export const PRINT_BATCH_CAPACITY_OFFSET = 4;
|
|
48
|
+
export const PRINT_BATCH_USED_OFFSET = 8;
|
|
49
|
+
export const PRINT_BATCH_RECORD_COUNT_OFFSET = 12;
|
|
50
|
+
export const PRINT_BATCH_OVERFLOW_OFFSET = 16;
|
|
51
|
+
export const EXECUTION_OUTPUT_DELEGATE_BATCH_OFFSET = 0;
|
|
52
|
+
export const EXECUTION_OUTPUT_PRINT_BATCH_OFFSET = 4;
|
|
53
|
+
export const EXECUTION_OUTPUT_SEQUENCE_OFFSET = 8;
|
|
54
|
+
export const RUNTIME_FAILURE_GLOBAL = "$onda.runtime_failure";
|
|
55
|
+
export const INIT_ALL_GLOBAL = "$onda.init_all";
|
|
56
|
+
export const MATH_KERNEL_INTRINSICS = new Set([
|
|
57
|
+
"sin",
|
|
58
|
+
"cos",
|
|
59
|
+
"tan",
|
|
60
|
+
"tanh",
|
|
61
|
+
"atan",
|
|
62
|
+
"atan2",
|
|
63
|
+
"exp",
|
|
64
|
+
"log",
|
|
65
|
+
"pow",
|
|
66
|
+
"remainder",
|
|
67
|
+
"fma",
|
|
68
|
+
]);
|
|
69
|
+
|
|
70
|
+
export const POINTER_GLOBALS = Object.freeze({
|
|
71
|
+
inputs: "$onda.inputs",
|
|
72
|
+
outputs: "$onda.outputs",
|
|
73
|
+
params: "$onda.params",
|
|
74
|
+
state: "$onda.state",
|
|
75
|
+
eventPayload: "$onda.event_payload",
|
|
76
|
+
delegateBatch: "$onda.delegate_batch",
|
|
77
|
+
printBatch: "$onda.print_batch",
|
|
78
|
+
outputSequence: "$onda.output_sequence",
|
|
79
|
+
buffers: "$onda.buffers",
|
|
80
|
+
bufferWrites: "$onda.buffer_writes",
|
|
81
|
+
bufferFrames: "$onda.buffer_frames",
|
|
82
|
+
bufferChannels: "$onda.buffer_channels",
|
|
83
|
+
bufferSampleRates: "$onda.buffer_sample_rates",
|
|
84
|
+
});
|
|
85
|
+
export const BUFFER_DESCRIPTOR_POINTER_GLOBALS = new Set([
|
|
86
|
+
POINTER_GLOBALS.buffers,
|
|
87
|
+
POINTER_GLOBALS.bufferWrites,
|
|
88
|
+
POINTER_GLOBALS.bufferFrames,
|
|
89
|
+
POINTER_GLOBALS.bufferChannels,
|
|
90
|
+
POINTER_GLOBALS.bufferSampleRates,
|
|
91
|
+
]);
|
|
92
|
+
export const TRAPPING_DESCRIPTOR_UNARY_OPS = new Set([
|
|
93
|
+
binaryen.TruncSFloat32ToInt32,
|
|
94
|
+
binaryen.TruncSFloat32ToInt64,
|
|
95
|
+
binaryen.TruncSFloat64ToInt32,
|
|
96
|
+
binaryen.TruncSFloat64ToInt64,
|
|
97
|
+
binaryen.TruncUFloat32ToInt32,
|
|
98
|
+
binaryen.TruncUFloat32ToInt64,
|
|
99
|
+
binaryen.TruncUFloat64ToInt32,
|
|
100
|
+
binaryen.TruncUFloat64ToInt64,
|
|
101
|
+
]);
|
|
102
|
+
export const TRAPPING_DESCRIPTOR_BINARY_OPS = new Set([
|
|
103
|
+
binaryen.DivSInt32,
|
|
104
|
+
binaryen.DivSInt64,
|
|
105
|
+
binaryen.DivUInt32,
|
|
106
|
+
binaryen.DivUInt64,
|
|
107
|
+
binaryen.RemSInt32,
|
|
108
|
+
binaryen.RemSInt64,
|
|
109
|
+
binaryen.RemUInt32,
|
|
110
|
+
binaryen.RemUInt64,
|
|
111
|
+
]);
|
|
112
|
+
|
|
113
|
+
export function collectMathKernelHelpers(mir) {
|
|
114
|
+
const result = new Set();
|
|
115
|
+
for (const func of mir?.functions ?? []) {
|
|
116
|
+
const localScalars = (func.locals ?? []).map((local) => {
|
|
117
|
+
const type = mir.types?.[local.ty];
|
|
118
|
+
return type?.kind === "scalar" ? type.data : null;
|
|
119
|
+
});
|
|
120
|
+
const valueScalar = (value) => {
|
|
121
|
+
if (value?.kind === "constant") return value.data?.type;
|
|
122
|
+
if (value?.kind === "local") return localScalars[value.data];
|
|
123
|
+
return null;
|
|
124
|
+
};
|
|
125
|
+
const visitBlock = (block) => {
|
|
126
|
+
for (const statement of block?.statements ?? []) {
|
|
127
|
+
const kind = statement.kind?.kind;
|
|
128
|
+
const data = statement.kind?.data;
|
|
129
|
+
if (kind === "assign" && data?.value?.kind === "intrinsic") {
|
|
130
|
+
const intrinsic = data.value.data?.intrinsic;
|
|
131
|
+
const scalar = valueScalar(data.value.data?.args?.[0]);
|
|
132
|
+
if (
|
|
133
|
+
MATH_KERNEL_INTRINSICS.has(intrinsic)
|
|
134
|
+
&& (scalar === "f32" || scalar === "f64")
|
|
135
|
+
) {
|
|
136
|
+
result.add(`onda_math_${intrinsic}_${scalar}`);
|
|
137
|
+
}
|
|
138
|
+
} else if (
|
|
139
|
+
kind === "assign"
|
|
140
|
+
&& data?.value?.kind === "binary"
|
|
141
|
+
&& data.value.data?.op === "remainder"
|
|
142
|
+
) {
|
|
143
|
+
const scalar = valueScalar(data.value.data?.lhs);
|
|
144
|
+
if (scalar === "f32" || scalar === "f64") {
|
|
145
|
+
result.add(`onda_math_remainder_${scalar}`);
|
|
146
|
+
}
|
|
147
|
+
} else if (kind === "if") {
|
|
148
|
+
visitBlock(data?.then_block);
|
|
149
|
+
visitBlock(data?.else_block);
|
|
150
|
+
} else if (kind === "loop") {
|
|
151
|
+
visitBlock(data?.body);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
visitBlock(func.body);
|
|
156
|
+
}
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function alignUp(value, alignment) {
|
|
161
|
+
return Math.ceil(value / alignment) * alignment;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function typeName(type, compiler) {
|
|
165
|
+
if (type.kind === "scalar") return type.data;
|
|
166
|
+
if (type.kind === "array") {
|
|
167
|
+
return `${typeName(compiler.type(type.data.element), compiler)}[${type.data.len}]`;
|
|
168
|
+
}
|
|
169
|
+
if (type.kind === "slice") return `${type.data.element}[]`;
|
|
170
|
+
return type.kind;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function encodeScalarValues(values, scalar, compiler) {
|
|
174
|
+
const size = compiler.scalarSize(scalar);
|
|
175
|
+
const bytes = new Uint8Array(values.length * size);
|
|
176
|
+
const view = new DataView(bytes.buffer);
|
|
177
|
+
values.forEach((value, index) => {
|
|
178
|
+
if (value.type !== scalar) {
|
|
179
|
+
compiler.fail(`const data scalar '${value.type}' does not match '${scalar}'`);
|
|
180
|
+
}
|
|
181
|
+
const offset = index * size;
|
|
182
|
+
switch (scalar) {
|
|
183
|
+
case "bool": view.setUint8(offset, value.value ? 1 : 0); break;
|
|
184
|
+
case "i32": view.setInt32(offset, value.value, true); break;
|
|
185
|
+
case "i64":
|
|
186
|
+
view.setBigInt64(offset, decodeI64Literal(value.value, compiler), true);
|
|
187
|
+
break;
|
|
188
|
+
case "f32":
|
|
189
|
+
view.setFloat32(offset, decodeFloatLiteral(value.value, "f32", compiler), true);
|
|
190
|
+
break;
|
|
191
|
+
case "f64":
|
|
192
|
+
view.setFloat64(offset, decodeFloatLiteral(value.value, "f64", compiler), true);
|
|
193
|
+
break;
|
|
194
|
+
default: compiler.fail(`unknown const data scalar '${String(scalar)}'`);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
return bytes;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export const I64_MIN = -(1n << 63n);
|
|
201
|
+
export const I64_MAX = (1n << 63n) - 1n;
|
|
202
|
+
|
|
203
|
+
export function decodeI64Literal(value, compiler) {
|
|
204
|
+
if (typeof value !== "string" || !/^-?(0|[1-9][0-9]*)$/.test(value)) {
|
|
205
|
+
compiler.fail(
|
|
206
|
+
`MIR schema ${SUPPORTED_MIR_SCHEMA_VERSION} i64 values must be canonical decimal strings`,
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
let decoded;
|
|
210
|
+
try {
|
|
211
|
+
decoded = BigInt(value);
|
|
212
|
+
} catch {
|
|
213
|
+
compiler.fail(`invalid MIR i64 value '${String(value)}'`);
|
|
214
|
+
}
|
|
215
|
+
if (decoded < I64_MIN || decoded > I64_MAX) {
|
|
216
|
+
compiler.fail(`MIR i64 value '${value}' is outside the signed 64-bit range`);
|
|
217
|
+
}
|
|
218
|
+
return decoded;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function decodeFloatLiteral(value, scalar, compiler) {
|
|
222
|
+
if (typeof value === "number") {
|
|
223
|
+
if (!Number.isFinite(value)) {
|
|
224
|
+
compiler.fail(`${scalar} JSON number must be finite`);
|
|
225
|
+
}
|
|
226
|
+
return value;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const digits = scalar === "f32" ? 8 : 16;
|
|
230
|
+
if (
|
|
231
|
+
typeof value !== "string"
|
|
232
|
+
|| !new RegExp(`^0x[0-9a-f]{${digits}}$`).test(value)
|
|
233
|
+
) {
|
|
234
|
+
compiler.fail(
|
|
235
|
+
`${scalar} value must be a finite JSON number or an exact ${digits}-digit IEEE bit pattern`,
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const bytes = new ArrayBuffer(8);
|
|
240
|
+
const view = new DataView(bytes);
|
|
241
|
+
if (scalar === "f32") {
|
|
242
|
+
view.setUint32(0, Number.parseInt(value.slice(2), 16), true);
|
|
243
|
+
return view.getFloat32(0, true);
|
|
244
|
+
}
|
|
245
|
+
view.setBigUint64(0, BigInt(value), true);
|
|
246
|
+
return view.getFloat64(0, true);
|
|
247
|
+
}
|