@gasm-compiler/core 0.1.0 → 0.1.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.
- package/README.md +146 -594
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,481 +1,49 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @gasm-compiler/core
|
|
2
2
|
|
|
3
3
|
**Compile WebAssembly to WGSL for GPU Execution**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Transform WebAssembly binaries into WGSL (WebGPU Shading Language) compute shaders. Write your GPU kernels in any language that compiles to WebAssembly (C, C++, Rust, Go, AssemblyScript, or hand-written WAT), then run them on the GPU via WebGPU.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
## Table of Contents
|
|
10
|
-
|
|
11
|
-
- [Overview](#overview)
|
|
12
|
-
- [Architecture](#architecture)
|
|
13
|
-
- [Compilation Pipeline](#compilation-pipeline)
|
|
14
|
-
- [IR Types](#ir-types)
|
|
15
|
-
- [Instruction Mapping](#instruction-mapping)
|
|
16
|
-
- [Gasm Conformance](#gasm-conformance)
|
|
17
|
-
- [Usage](#usage)
|
|
18
|
-
- [Testing](#testing)
|
|
19
|
-
- [API Reference](#api-reference)
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## Overview
|
|
24
|
-
|
|
25
|
-
**Gasm Compiler Core** is a TypeScript/Deno compiler that:
|
|
26
|
-
|
|
27
|
-
1. **Parses** WebAssembly binaries (Wasm Core 1.0)
|
|
28
|
-
2. **Validates** GPU execution constraints (Gasm spec)
|
|
29
|
-
3. **Transforms** stack-based Wasm to structured WGSL
|
|
30
|
-
4. **Generates** WGSL compute shaders ready for WebGPU
|
|
31
|
-
|
|
32
|
-
### Key Features
|
|
33
|
-
|
|
34
|
-
- ✅ Full L0 conformance (scalar operations)
|
|
35
|
-
- ✅ 120+ WebAssembly instructions supported
|
|
36
|
-
- ✅ Control flow restructuring (Relooper algorithm)
|
|
37
|
-
- ✅ Memory operation lowering (sub-word access)
|
|
38
|
-
- ✅ Global imports and Gasm built-ins
|
|
39
|
-
- ✅ Type-safe SSA intermediate representation
|
|
40
|
-
- 🚧 L1/L2 conformance (SIMD, atomics) — planned
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## Architecture
|
|
45
|
-
|
|
46
|
-
The compiler uses a **5-phase pipeline** to transform WebAssembly into WGSL:
|
|
47
|
-
|
|
48
|
-
```
|
|
49
|
-
┌─────────────┐
|
|
50
|
-
│ Wasm Binary │ Input: .wasm file (Uint8Array)
|
|
51
|
-
└──────┬──────┘
|
|
52
|
-
│
|
|
53
|
-
v
|
|
54
|
-
┌─────────────┐
|
|
55
|
-
│ Phase 1: │ Parse & Validate
|
|
56
|
-
│ Parser │ • Binary format parsing
|
|
57
|
-
│ │ • Gasm restriction validation (Section 10)
|
|
58
|
-
└──────┬──────┘ • Output: WasmModule (stack-based IR)
|
|
59
|
-
│
|
|
60
|
-
v
|
|
61
|
-
┌─────────────┐
|
|
62
|
-
│ Phase 2: │ Stack → SSA Conversion
|
|
63
|
-
│ SSA IR │ • Convert stack operations to SSA form
|
|
64
|
-
│ │ • Type inference for locals
|
|
65
|
-
└──────┬──────┘ • Output: SSAModule (SSA IR)
|
|
66
|
-
│
|
|
67
|
-
v
|
|
68
|
-
┌─────────────┐
|
|
69
|
-
│ Phase 3: │ Control Flow Restructuring
|
|
70
|
-
│ Relooper │ • Transform unstructured jumps (br, br_if, br_table)
|
|
71
|
-
│ │ • Generate structured blocks/loops
|
|
72
|
-
└──────┬──────┘ • Output: StructuredModule
|
|
73
|
-
│
|
|
74
|
-
v
|
|
75
|
-
┌─────────────┐
|
|
76
|
-
│ Phase 4: │ Memory Lowering
|
|
77
|
-
│ MemLower │ • Lower i8/i16 loads/stores to i32 word access
|
|
78
|
-
│ │ • Generate bit-masking and shifting
|
|
79
|
-
└──────┬──────┘ • Output: StructuredModule (memory-lowered)
|
|
80
|
-
│
|
|
81
|
-
v
|
|
82
|
-
┌─────────────┐
|
|
83
|
-
│ Phase 5: │ WGSL Code Generation
|
|
84
|
-
│ Codegen │ • Emit WGSL functions, variables, structs
|
|
85
|
-
│ │ • Map Wasm instructions to WGSL expressions
|
|
86
|
-
└──────┬──────┘ • Output: WGSL string
|
|
87
|
-
│
|
|
88
|
-
v
|
|
89
|
-
┌─────────────┐
|
|
90
|
-
│ WGSL Code │ Output: Valid WebGPU shader
|
|
91
|
-
└─────────────┘
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
---
|
|
95
|
-
|
|
96
|
-
## Compilation Pipeline
|
|
97
|
-
|
|
98
|
-
### Phase 1: Parse & Validate
|
|
99
|
-
|
|
100
|
-
**File:** `src/parser.ts`
|
|
101
|
-
**Input:** WebAssembly binary (`Uint8Array`)
|
|
102
|
-
**Output:** `WasmModule` (stack-based IR)
|
|
103
|
-
|
|
104
|
-
**Responsibilities:**
|
|
105
|
-
- Parse Wasm binary format (magic, version, sections)
|
|
106
|
-
- Extract types, imports, functions, tables, memories, globals, exports, code
|
|
107
|
-
- Validate Gasm restrictions:
|
|
108
|
-
- Max 1 memory (no multi-memory)
|
|
109
|
-
- Max 1 table (no multi-table)
|
|
110
|
-
- No imports except globals (built-ins)
|
|
111
|
-
- Memory must be exported as `"memory"`
|
|
112
|
-
- Decode instruction bytecode to IR
|
|
113
|
-
|
|
114
|
-
**Key Functions:**
|
|
115
|
-
```typescript
|
|
116
|
-
export function parseWasm(binary: Uint8Array): WasmModule
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
**Error Handling:**
|
|
120
|
-
Throws `CompileError` with descriptive message for invalid binaries or Gasm violations.
|
|
121
|
-
|
|
122
|
-
---
|
|
123
|
-
|
|
124
|
-
### Phase 2: Stack → SSA Conversion
|
|
125
|
-
|
|
126
|
-
**File:** `src/phases.ts` → `phaseStackToSSA()`
|
|
127
|
-
**Input:** `WasmModule`
|
|
128
|
-
**Output:** `SSAModule`
|
|
129
|
-
|
|
130
|
-
**Responsibilities:**
|
|
131
|
-
- Convert stack-based operations to Static Single Assignment (SSA) form
|
|
132
|
-
- Infer types for local variables (from usage patterns)
|
|
133
|
-
- Preserve global definitions and imports
|
|
134
|
-
- Generate unique SSA variable names (`%0`, `%1`, `%2`, ...)
|
|
135
|
-
|
|
136
|
-
**Example:**
|
|
137
|
-
```wasm
|
|
138
|
-
;; WebAssembly (stack-based)
|
|
139
|
-
local.get 0
|
|
140
|
-
i32.const 1
|
|
141
|
-
i32.add
|
|
142
|
-
local.set 0
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
↓
|
|
146
|
-
|
|
147
|
-
```
|
|
148
|
-
// SSA IR
|
|
149
|
-
%0 = local.get 0: i32
|
|
150
|
-
%1 = i32.const 1
|
|
151
|
-
%2 = i32.add %0, %1
|
|
152
|
-
local.set 0, %2
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
**Key Functions:**
|
|
156
|
-
```typescript
|
|
157
|
-
export function phaseStackToSSA(module: WasmModule): SSAModule
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
---
|
|
161
|
-
|
|
162
|
-
### Phase 3: Control Flow Restructuring
|
|
163
|
-
|
|
164
|
-
**File:** `src/relooper.ts`
|
|
165
|
-
**Input:** `SSAModule`
|
|
166
|
-
**Output:** `StructuredModule`
|
|
167
|
-
|
|
168
|
-
**Responsibilities:**
|
|
169
|
-
- Apply the **Relooper algorithm** to restructure control flow
|
|
170
|
-
- Transform unstructured jumps (`br`, `br_if`, `br_table`) into structured loops/blocks
|
|
171
|
-
- Generate WGSL-compatible control structures (`if`, `loop`, `break`, `continue`)
|
|
172
|
-
|
|
173
|
-
**Example:**
|
|
174
|
-
```wasm
|
|
175
|
-
;; WebAssembly (unstructured)
|
|
176
|
-
block $exit
|
|
177
|
-
loop $loop
|
|
178
|
-
local.get 0
|
|
179
|
-
i32.const 10
|
|
180
|
-
i32.lt_s
|
|
181
|
-
br_if $exit
|
|
182
|
-
;; loop body
|
|
183
|
-
br $loop
|
|
184
|
-
end
|
|
185
|
-
end
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
↓
|
|
189
|
-
|
|
190
|
-
```wgsl
|
|
191
|
-
// WGSL (structured)
|
|
192
|
-
loop {
|
|
193
|
-
if (var_0 < 10i) { break; }
|
|
194
|
-
// loop body
|
|
195
|
-
}
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
**Key Functions:**
|
|
199
|
-
```typescript
|
|
200
|
-
export function reloop(module: SSAModule): StructuredModule
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
---
|
|
204
|
-
|
|
205
|
-
### Phase 4: Memory Lowering
|
|
206
|
-
|
|
207
|
-
**File:** `src/phases.ts` → `phaseMemoryLowering()`
|
|
208
|
-
**Input:** `StructuredModule`
|
|
209
|
-
**Output:** `StructuredModule` (memory-lowered)
|
|
210
|
-
|
|
211
|
-
**Responsibilities:**
|
|
212
|
-
- Lower sub-word memory operations (i8/i16) to word-aligned access (i32)
|
|
213
|
-
- Generate bit-masking and shifting for unaligned access
|
|
214
|
-
- Preserve i32/i64/f32/f64 memory operations
|
|
215
|
-
|
|
216
|
-
**Example:**
|
|
217
|
-
```wasm
|
|
218
|
-
;; i32.load8_u offset=0 align=1
|
|
219
|
-
i32.load8_u offset=0 align=1
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
↓
|
|
223
|
-
|
|
224
|
-
```wgsl
|
|
225
|
-
// WGSL (lowered to word access)
|
|
226
|
-
let word_addr = offset / 4u;
|
|
227
|
-
let byte_offset = offset % 4u;
|
|
228
|
-
let word = memory[word_addr];
|
|
229
|
-
let byte = (word >> (byte_offset * 8u)) & 0xFFu;
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
**Key Functions:**
|
|
233
|
-
```typescript
|
|
234
|
-
export function phaseMemoryLowering(module: StructuredModule): StructuredModule
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
---
|
|
238
|
-
|
|
239
|
-
### Phase 5: WGSL Code Generation
|
|
240
|
-
|
|
241
|
-
**File:** `src/phases.ts` → `phaseWgslCodegen()`
|
|
242
|
-
**Input:** `StructuredModule`
|
|
243
|
-
**Output:** WGSL string
|
|
244
|
-
|
|
245
|
-
**Responsibilities:**
|
|
246
|
-
- Emit WGSL variable declarations (globals, locals)
|
|
247
|
-
- Emit function definitions with signatures
|
|
248
|
-
- Emit main entry point with Gasm built-in parameters:
|
|
249
|
-
- `@builtin(global_invocation_id)` → `global_invocation_id_{x,y,z}`
|
|
250
|
-
- `@builtin(local_invocation_id)` → `local_invocation_id_{x,y,z}`
|
|
251
|
-
- `@builtin(workgroup_id)` → `workgroup_id_{x,y,z}`
|
|
252
|
-
- `@builtin(num_workgroups)` → `num_workgroups_{x,y,z}`
|
|
253
|
-
- Map Wasm instructions to WGSL expressions
|
|
254
|
-
- Generate structured control flow (blocks, loops, conditionals)
|
|
255
|
-
|
|
256
|
-
**Example:**
|
|
257
|
-
```wasm
|
|
258
|
-
(func $add (param i32 i32) (result i32)
|
|
259
|
-
local.get 0
|
|
260
|
-
local.get 1
|
|
261
|
-
i32.add)
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
↓
|
|
265
|
-
|
|
266
|
-
```wgsl
|
|
267
|
-
fn func_0(param_0: i32, param_1: i32) -> i32 {
|
|
268
|
-
return param_0 + param_1;
|
|
269
|
-
}
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
**Key Functions:**
|
|
273
|
-
```typescript
|
|
274
|
-
export function phaseWgslCodegen(
|
|
275
|
-
module: StructuredModule,
|
|
276
|
-
options?: CompileOptions
|
|
277
|
-
): string
|
|
278
|
-
```
|
|
7
|
+
Implements the [Gasm v0.1 specification](https://github.com/gasm-compiler/spec) — a GPU-executable subset of WebAssembly.
|
|
279
8
|
|
|
280
9
|
---
|
|
281
10
|
|
|
282
|
-
##
|
|
283
|
-
|
|
284
|
-
The compiler uses three IR representations:
|
|
11
|
+
## Installation
|
|
285
12
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
**File:** `src/types.ts`
|
|
289
|
-
**Purpose:** Direct representation of WebAssembly binary
|
|
290
|
-
|
|
291
|
-
```typescript
|
|
292
|
-
export interface WasmModule {
|
|
293
|
-
types: WasmType[];
|
|
294
|
-
imports: Import[];
|
|
295
|
-
functions: WasmFunction[];
|
|
296
|
-
tables: Table[];
|
|
297
|
-
memories: Memory[];
|
|
298
|
-
globals: Global[]; // ImportedGlobal | DefinedGlobal
|
|
299
|
-
exports: Export[];
|
|
300
|
-
start?: number;
|
|
301
|
-
elements: Element[];
|
|
302
|
-
dataSegments: DataSegment[];
|
|
303
|
-
customSections: CustomSection[];
|
|
304
|
-
}
|
|
13
|
+
```bash
|
|
14
|
+
npm install @gasm-compiler/core
|
|
305
15
|
```
|
|
306
16
|
|
|
307
|
-
**
|
|
308
|
-
- `types`: Function signatures (param/result types)
|
|
309
|
-
- `functions`: Function bodies with stack-based instructions
|
|
310
|
-
- `globals`: Global variables (imported built-ins or definitions)
|
|
311
|
-
- `memories`: Linear memory configuration (initial/max pages)
|
|
312
|
-
- `exports`: Exported functions and memory
|
|
17
|
+
**Requirements:** TypeScript 5.0+ (peer dependency)
|
|
313
18
|
|
|
314
19
|
---
|
|
315
20
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
**File:** `src/types.ts`
|
|
319
|
-
**Purpose:** Static Single Assignment form for analysis
|
|
21
|
+
## Quick Start
|
|
320
22
|
|
|
321
23
|
```typescript
|
|
322
|
-
|
|
323
|
-
types: WasmType[];
|
|
324
|
-
imports: Import[];
|
|
325
|
-
functions: SSAFunction[];
|
|
326
|
-
tables: Table[];
|
|
327
|
-
memories: Memory[];
|
|
328
|
-
globals: Global[];
|
|
329
|
-
exports: Export[];
|
|
330
|
-
start?: number;
|
|
331
|
-
elements: Element[];
|
|
332
|
-
dataSegments: DataSegment[];
|
|
333
|
-
customSections: CustomSection[];
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
export interface SSAFunction {
|
|
337
|
-
typeIndex: number;
|
|
338
|
-
locals: Local[];
|
|
339
|
-
body: SSAInstruction[];
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
export interface SSAInstruction {
|
|
343
|
-
opcode: number;
|
|
344
|
-
name: string;
|
|
345
|
-
type?: string;
|
|
346
|
-
operands?: string[];
|
|
347
|
-
result?: string;
|
|
348
|
-
immediates?: unknown[];
|
|
349
|
-
}
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
**Key Properties:**
|
|
353
|
-
- `SSAFunction.body`: Instructions with explicit SSA operands/results
|
|
354
|
-
- `SSAInstruction.result`: SSA variable name (e.g., `%0`, `%1`)
|
|
355
|
-
- `SSAInstruction.operands`: SSA variable dependencies (e.g., `["%0", "%1"]`)
|
|
356
|
-
|
|
357
|
-
---
|
|
358
|
-
|
|
359
|
-
### 3. StructuredModule (Structured IR)
|
|
360
|
-
|
|
361
|
-
**File:** `src/types.ts`
|
|
362
|
-
**Purpose:** Structured control flow for WGSL generation
|
|
24
|
+
import { compile } from "@gasm-compiler/core";
|
|
363
25
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
types: WasmType[];
|
|
367
|
-
imports: Import[];
|
|
368
|
-
functions: StructuredFunction[];
|
|
369
|
-
tables: Table[];
|
|
370
|
-
memories: Memory[];
|
|
371
|
-
globals: Global[];
|
|
372
|
-
exports: Export[];
|
|
373
|
-
start?: number;
|
|
374
|
-
elements: Element[];
|
|
375
|
-
dataSegments: DataSegment[];
|
|
376
|
-
customSections: CustomSection[];
|
|
377
|
-
}
|
|
26
|
+
// Load a WebAssembly binary (.wasm file)
|
|
27
|
+
const wasmBytes = new Uint8Array(await fetch("shader.wasm").then(r => r.arrayBuffer()));
|
|
378
28
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
locals: Local[];
|
|
382
|
-
body: StructuredInstruction[];
|
|
383
|
-
}
|
|
29
|
+
// Compile to WGSL
|
|
30
|
+
const wgslCode = compile(wasmBytes);
|
|
384
31
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
name: string;
|
|
388
|
-
type?: string;
|
|
389
|
-
operands?: string[];
|
|
390
|
-
result?: string;
|
|
391
|
-
immediates?: unknown[];
|
|
392
|
-
}
|
|
32
|
+
// Use with WebGPU
|
|
33
|
+
const shaderModule = device.createShaderModule({ code: wgslCode });
|
|
393
34
|
```
|
|
394
35
|
|
|
395
|
-
**Key Properties:**
|
|
396
|
-
- Control flow is fully structured (no `br`, `br_if`, `br_table`)
|
|
397
|
-
- Instructions use WGSL-compatible constructs (`if`, `loop`, `break`)
|
|
398
|
-
- Memory operations are word-aligned (i32/i64/f32/f64 only)
|
|
399
|
-
|
|
400
|
-
---
|
|
401
|
-
|
|
402
|
-
## Instruction Mapping
|
|
403
|
-
|
|
404
|
-
The compiler maps 120+ WebAssembly instructions to WGSL equivalents. See the full table in the [Instruction Set Reference](../../docs/instruction-set.md).
|
|
405
|
-
|
|
406
|
-
### Quick Reference
|
|
407
|
-
|
|
408
|
-
| Category | Example Instructions | WGSL Equivalent |
|
|
409
|
-
|----------|---------------------|-----------------|
|
|
410
|
-
| **Arithmetic** | `i32.add`, `f32.mul` | `a + b`, `a * b` |
|
|
411
|
-
| **Bitwise** | `i32.and`, `i32.shl` | `a & b`, `a << (b & 31u)` |
|
|
412
|
-
| **Comparisons** | `i32.lt_s`, `f32.eq` | `a < b`, `a == b` |
|
|
413
|
-
| **Memory** | `i32.load`, `i32.store8` | `memory[addr/4u]`, bit-masking |
|
|
414
|
-
| **Conversions** | `i32.trunc_f32_s`, `f32.convert_i32_u` | `i32(trunc(a))`, `f32(u32(a))` |
|
|
415
|
-
| **Control Flow** | `block`, `loop`, `br_if` | `{ ... }`, `loop { ... }`, `if (c) { break; }` |
|
|
416
|
-
| **Variables** | `local.get`, `global.set` | `var_N`, `global_N = val` |
|
|
417
|
-
| **Special** | `select`, `memory.size` | `select(a, b, c)`, `arrayLength(&memory)` |
|
|
418
|
-
|
|
419
36
|
---
|
|
420
37
|
|
|
421
|
-
##
|
|
38
|
+
## Features
|
|
422
39
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
| **L1 (SIMD)** | 128-bit SIMD operations (v128) | 🚧 Planned |
|
|
431
|
-
| **L2 (Extended)** | Atomics + Relaxed SIMD | 🚧 Planned |
|
|
432
|
-
|
|
433
|
-
### Gasm Restrictions (Section 10)
|
|
434
|
-
|
|
435
|
-
The compiler enforces these restrictions during Phase 1 validation:
|
|
436
|
-
|
|
437
|
-
1. **Single Memory**: Max 1 memory, must be exported as `"memory"`
|
|
438
|
-
2. **Single Table**: Max 1 table (for indirect calls)
|
|
439
|
-
3. **No Imports** (except globals): Only global imports allowed (Gasm built-ins)
|
|
440
|
-
4. **Deterministic Execution**: No `unreachable` or trapping operations in production code
|
|
441
|
-
5. **Structured Control Flow**: All `br`, `br_if`, `br_table` must be restructurable (Phase 3)
|
|
442
|
-
|
|
443
|
-
### Gasm Built-in Globals
|
|
444
|
-
|
|
445
|
-
The compiler automatically maps WGSL built-ins to global imports:
|
|
446
|
-
|
|
447
|
-
| Global Name | WGSL Built-in | Type |
|
|
448
|
-
|-------------|---------------|------|
|
|
449
|
-
| `global_invocation_id_x` | `@builtin(global_invocation_id).x` | `u32` |
|
|
450
|
-
| `global_invocation_id_y` | `@builtin(global_invocation_id).y` | `u32` |
|
|
451
|
-
| `global_invocation_id_z` | `@builtin(global_invocation_id).z` | `u32` |
|
|
452
|
-
| `local_invocation_id_x` | `@builtin(local_invocation_id).x` | `u32` |
|
|
453
|
-
| `local_invocation_id_y` | `@builtin(local_invocation_id).y` | `u32` |
|
|
454
|
-
| `local_invocation_id_z` | `@builtin(local_invocation_id).z` | `u32` |
|
|
455
|
-
| `workgroup_id_x` | `@builtin(workgroup_id).x` | `u32` |
|
|
456
|
-
| `workgroup_id_y` | `@builtin(workgroup_id).y` | `u32` |
|
|
457
|
-
| `workgroup_id_z` | `@builtin(workgroup_id).z` | `u32` |
|
|
458
|
-
| `num_workgroups_x` | `@builtin(num_workgroups).x` | `u32` |
|
|
459
|
-
| `num_workgroups_y` | `@builtin(num_workgroups).y` | `u32` |
|
|
460
|
-
| `num_workgroups_z` | `@builtin(num_workgroups).z` | `u32` |
|
|
461
|
-
|
|
462
|
-
**Example:**
|
|
463
|
-
```wasm
|
|
464
|
-
(import "gasm" "global_invocation_id_x" (global $gid_x i32))
|
|
465
|
-
```
|
|
466
|
-
|
|
467
|
-
↓
|
|
468
|
-
|
|
469
|
-
```wgsl
|
|
470
|
-
@compute @workgroup_size(64)
|
|
471
|
-
fn main(
|
|
472
|
-
@builtin(global_invocation_id) global_invocation_id: vec3<u32>,
|
|
473
|
-
// ... other built-ins
|
|
474
|
-
) {
|
|
475
|
-
var global_invocation_id_x: u32 = global_invocation_id.x;
|
|
476
|
-
// ... use in function body
|
|
477
|
-
}
|
|
478
|
-
```
|
|
40
|
+
- 120+ WebAssembly instructions mapped to WGSL equivalents
|
|
41
|
+
- Full L0 conformance (i32, i64, f32, f64 scalar operations)
|
|
42
|
+
- Control flow restructuring — WebAssembly's unstructured branches become WGSL loops/blocks
|
|
43
|
+
- Sub-word memory access — i8/i16 loads/stores lowered to word-aligned operations
|
|
44
|
+
- Gasm built-in globals for GPU thread identification
|
|
45
|
+
- Optional math extension for direct WGSL built-in math calls
|
|
46
|
+
- Works in Node.js, Deno, and browsers
|
|
479
47
|
|
|
480
48
|
---
|
|
481
49
|
|
|
@@ -486,51 +54,42 @@ fn main(
|
|
|
486
54
|
```typescript
|
|
487
55
|
import { compile } from "@gasm-compiler/core";
|
|
488
56
|
|
|
489
|
-
// Load WebAssembly binary
|
|
490
|
-
const wasmBytes = await Deno.readFile("shader.wasm");
|
|
491
|
-
|
|
492
|
-
// Compile to WGSL
|
|
493
57
|
const wgslCode = compile(wasmBytes);
|
|
494
|
-
|
|
495
|
-
// Use with WebGPU
|
|
496
|
-
const shaderModule = device.createShaderModule({ code: wgslCode });
|
|
497
58
|
```
|
|
498
59
|
|
|
499
|
-
###
|
|
60
|
+
### Compilation Options
|
|
500
61
|
|
|
501
62
|
```typescript
|
|
502
|
-
import { compile
|
|
63
|
+
import { compile } from "@gasm-compiler/core";
|
|
503
64
|
|
|
504
|
-
const
|
|
65
|
+
const wgslCode = compile(wasmBytes, {
|
|
505
66
|
workgroupSize: [128, 1, 1], // Default: [64, 1, 1]
|
|
506
|
-
debug: true, // Emit
|
|
67
|
+
debug: true, // Emit source-mapping comments
|
|
507
68
|
mathExtension: true, // Enable gasm:math built-ins
|
|
508
|
-
};
|
|
509
|
-
|
|
510
|
-
const wgslCode = compile(wasmBytes, options);
|
|
69
|
+
});
|
|
511
70
|
```
|
|
512
71
|
|
|
513
|
-
### Math Extension
|
|
72
|
+
### Math Extension
|
|
514
73
|
|
|
515
|
-
|
|
74
|
+
Enable direct mapping of WebAssembly imports to WGSL built-in math functions:
|
|
516
75
|
|
|
517
76
|
```typescript
|
|
518
|
-
import { compile } from "@gasm-compiler/core";
|
|
519
|
-
|
|
520
77
|
const wgslCode = compile(wasmBytes, {
|
|
521
|
-
mathExtension: true,
|
|
522
|
-
// or: mathExtension: "M0"
|
|
523
|
-
// or: mathExtension: "M1"
|
|
524
|
-
// or: mathExtension: "M2"
|
|
78
|
+
mathExtension: true, // Enable all levels (M0, M1, M2)
|
|
79
|
+
// or: mathExtension: "M0" // Core scalar functions only
|
|
80
|
+
// or: mathExtension: "M1" // Core + vector functions
|
|
81
|
+
// or: mathExtension: "M2" // All functions
|
|
525
82
|
});
|
|
526
83
|
```
|
|
527
84
|
|
|
528
|
-
When enabled, imports like `(import "gasm" "sin" (func ...))`
|
|
85
|
+
When enabled, WebAssembly imports like `(import "gasm" "sin" (func ...))` compile to direct WGSL built-in calls (`sin(...)`) with zero overhead.
|
|
529
86
|
|
|
530
87
|
**Math Levels:**
|
|
531
|
-
- **M0 (Core)
|
|
532
|
-
- **M1 (Vector)
|
|
533
|
-
- **M2 (Advanced)
|
|
88
|
+
- **M0 (Core):** sin, cos, sqrt, abs, min, max, clamp, floor, ceil, etc.
|
|
89
|
+
- **M1 (Vector):** length, dot, cross, normalize, reflect, refract, etc.
|
|
90
|
+
- **M2 (Advanced):** modf, frexp, ldexp, degrees, radians, bit manipulation
|
|
91
|
+
|
|
92
|
+
> See also: [`@gasm-compiler/math-reference`](https://www.npmjs.com/package/@gasm-compiler/math-reference) for CPU-side reference implementations of these math functions.
|
|
534
93
|
|
|
535
94
|
### Error Handling
|
|
536
95
|
|
|
@@ -539,7 +98,6 @@ import { compile, isCompileError } from "@gasm-compiler/core";
|
|
|
539
98
|
|
|
540
99
|
try {
|
|
541
100
|
const wgslCode = compile(wasmBytes);
|
|
542
|
-
console.log("Compilation successful!");
|
|
543
101
|
} catch (error) {
|
|
544
102
|
if (isCompileError(error)) {
|
|
545
103
|
console.error("Compile Error:", error.message);
|
|
@@ -547,123 +105,144 @@ try {
|
|
|
547
105
|
console.error(` at line ${error.location.line}, column ${error.location.column}`);
|
|
548
106
|
}
|
|
549
107
|
} else {
|
|
550
|
-
throw error;
|
|
108
|
+
throw error;
|
|
551
109
|
}
|
|
552
110
|
}
|
|
553
111
|
```
|
|
554
112
|
|
|
555
|
-
|
|
113
|
+
### Browser Usage
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
import { compile } from "@gasm-compiler/core/browser";
|
|
117
|
+
|
|
118
|
+
const wgslCode = compile(wasmBytes);
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Using with WebGPU
|
|
556
122
|
|
|
557
|
-
|
|
123
|
+
```typescript
|
|
124
|
+
import { compile } from "@gasm-compiler/core";
|
|
558
125
|
|
|
559
|
-
|
|
126
|
+
// 1. Compile Wasm → WGSL
|
|
127
|
+
const wgslCode = compile(wasmBytes, { workgroupSize: [256, 1, 1] });
|
|
560
128
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
pnpm test:core
|
|
129
|
+
// 2. Create shader module
|
|
130
|
+
const shaderModule = device.createShaderModule({ code: wgslCode });
|
|
564
131
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
132
|
+
// 3. Create compute pipeline
|
|
133
|
+
const pipeline = device.createComputePipeline({
|
|
134
|
+
layout: "auto",
|
|
135
|
+
compute: { module: shaderModule, entryPoint: "main" },
|
|
136
|
+
});
|
|
568
137
|
|
|
569
|
-
|
|
570
|
-
|
|
138
|
+
// 4. Dispatch
|
|
139
|
+
const commandEncoder = device.createCommandEncoder();
|
|
140
|
+
const pass = commandEncoder.beginComputePass();
|
|
141
|
+
pass.setPipeline(pipeline);
|
|
142
|
+
pass.setBindGroup(0, bindGroup);
|
|
143
|
+
pass.dispatchWorkgroups(numWorkgroups);
|
|
144
|
+
pass.end();
|
|
145
|
+
device.queue.submit([commandEncoder.finish()]);
|
|
571
146
|
```
|
|
572
147
|
|
|
573
|
-
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## How It Works
|
|
574
151
|
|
|
575
|
-
|
|
152
|
+
The compiler transforms WebAssembly into WGSL through a multi-phase pipeline:
|
|
576
153
|
|
|
577
154
|
```
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
155
|
+
WebAssembly Binary (.wasm)
|
|
156
|
+
↓
|
|
157
|
+
Parse & Validate (Gasm restrictions)
|
|
158
|
+
↓
|
|
159
|
+
Convert to SSA form
|
|
160
|
+
↓
|
|
161
|
+
Restructure control flow (Relooper)
|
|
162
|
+
↓
|
|
163
|
+
Lower memory operations
|
|
164
|
+
↓
|
|
165
|
+
WGSL Code Generation
|
|
166
|
+
↓
|
|
167
|
+
WGSL Compute Shader (.wgsl)
|
|
581
168
|
```
|
|
582
169
|
|
|
583
|
-
|
|
584
|
-
- ✅ **Phase 1: Parser validation** (26 tests)
|
|
585
|
-
- ✅ **Phase 2-5: Integration tests** (12 tests)
|
|
586
|
-
- ✅ **i32 Arithmetic** (18 tests)
|
|
587
|
-
- ✅ **i32 Bitwise** (32 tests)
|
|
588
|
-
- ✅ **i32 Comparison** (20 tests)
|
|
589
|
-
- ✅ **i64 Arithmetic** (19 tests)
|
|
590
|
-
- ✅ **i64 Bitwise** (32 tests)
|
|
591
|
-
- ✅ **i64 Comparison** (20 tests)
|
|
592
|
-
- ✅ **f32 Arithmetic** (48 tests)
|
|
593
|
-
- ✅ **f64 Arithmetic** (48 tests)
|
|
594
|
-
- ✅ **Float Comparison** (17 tests)
|
|
595
|
-
- ✅ **Float Edge Cases** (18 tests)
|
|
596
|
-
- ✅ **Type Conversions** (53 tests: 16 original + 37 new comprehensive tests)
|
|
597
|
-
- ✅ **Control Flow** (9 tests)
|
|
598
|
-
- ✅ **Memory Operations** (14 tests)
|
|
599
|
-
- ✅ **Functions, Stack, Constants** (19 tests)
|
|
600
|
-
- ✅ **Error Handling** (19 tests)
|
|
601
|
-
- ✅ **WGSL Output Validation** (40 tests)
|
|
602
|
-
- ✅ **Global & Options** (2 tests)
|
|
603
|
-
|
|
604
|
-
**Total:** 471 tests passing (414ms execution time)
|
|
605
|
-
**Test Files:** 23 organized by instruction category
|
|
606
|
-
|
|
607
|
-
### Adding New Tests
|
|
170
|
+
### Gasm Restrictions
|
|
608
171
|
|
|
609
|
-
|
|
610
|
-
import { assertEquals } from "jsr:@std/assert";
|
|
611
|
-
import { compile } from "../src/mod.ts";
|
|
612
|
-
|
|
613
|
-
Deno.test("Compiler - Feature Name", () => {
|
|
614
|
-
// Create WebAssembly binary (WAT → Wasm)
|
|
615
|
-
const wat = `
|
|
616
|
-
(module
|
|
617
|
-
(func (export "add") (param i32 i32) (result i32)
|
|
618
|
-
local.get 0
|
|
619
|
-
local.get 1
|
|
620
|
-
i32.add))
|
|
621
|
-
`;
|
|
622
|
-
const wasmBytes = wat2wasm(wat); // Use wat2wasm utility
|
|
623
|
-
|
|
624
|
-
// Compile to WGSL
|
|
625
|
-
const wgslCode = compile(wasmBytes);
|
|
172
|
+
Your WebAssembly module must conform to the Gasm subset:
|
|
626
173
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
174
|
+
- **Single memory** — max 1 linear memory, exported as `"memory"`
|
|
175
|
+
- **Single table** — max 1 table (for indirect calls)
|
|
176
|
+
- **Global imports only** — no function or memory imports (except Gasm built-in globals)
|
|
177
|
+
- **Structured control flow** — all branches must be restructurable
|
|
178
|
+
|
|
179
|
+
### Gasm Built-in Globals
|
|
180
|
+
|
|
181
|
+
Import GPU thread identifiers as WebAssembly globals from the `"gasm"` module:
|
|
182
|
+
|
|
183
|
+
| Import Name | Maps to WGSL | Type |
|
|
184
|
+
|-------------|--------------|------|
|
|
185
|
+
| `global_invocation_id_x/y/z` | `@builtin(global_invocation_id)` | `u32` |
|
|
186
|
+
| `local_invocation_id_x/y/z` | `@builtin(local_invocation_id)` | `u32` |
|
|
187
|
+
| `workgroup_id_x/y/z` | `@builtin(workgroup_id)` | `u32` |
|
|
188
|
+
| `num_workgroups_x/y/z` | `@builtin(num_workgroups)` | `u32` |
|
|
189
|
+
|
|
190
|
+
**Example (WAT):**
|
|
191
|
+
```wasm
|
|
192
|
+
(module
|
|
193
|
+
(import "gasm" "global_invocation_id_x" (global $gid_x i32))
|
|
194
|
+
(memory (export "memory") 1)
|
|
195
|
+
(func (export "main")
|
|
196
|
+
;; Use $gid_x to index into memory per-thread
|
|
197
|
+
))
|
|
630
198
|
```
|
|
631
199
|
|
|
200
|
+
### Instruction Support
|
|
201
|
+
|
|
202
|
+
| Category | Examples | WGSL Output |
|
|
203
|
+
|----------|---------|-------------|
|
|
204
|
+
| Arithmetic | `i32.add`, `f32.mul` | `a + b`, `a * b` |
|
|
205
|
+
| Bitwise | `i32.and`, `i32.shl` | `a & b`, `a << (b & 31u)` |
|
|
206
|
+
| Comparisons | `i32.lt_s`, `f32.eq` | `a < b`, `a == b` |
|
|
207
|
+
| Memory | `i32.load`, `i32.store8` | `memory[addr/4u]`, bit-masking |
|
|
208
|
+
| Conversions | `i32.trunc_f32_s` | `i32(trunc(a))` |
|
|
209
|
+
| Control Flow | `block`, `loop`, `br_if` | `loop { ... }`, `if (c) { break; }` |
|
|
210
|
+
| Variables | `local.get`, `global.set` | `var_N`, `global_N = val` |
|
|
211
|
+
|
|
632
212
|
---
|
|
633
213
|
|
|
634
214
|
## API Reference
|
|
635
215
|
|
|
636
|
-
###
|
|
216
|
+
### `compile(source, options?)`
|
|
637
217
|
|
|
638
|
-
|
|
218
|
+
```typescript
|
|
219
|
+
function compile(source: Uint8Array, options?: CompileOptions): string
|
|
220
|
+
```
|
|
639
221
|
|
|
640
222
|
Compiles a WebAssembly binary to WGSL.
|
|
641
223
|
|
|
642
224
|
**Parameters:**
|
|
643
|
-
- `source
|
|
644
|
-
- `options
|
|
645
|
-
|
|
646
|
-
**Returns:** WGSL shader code (string)
|
|
225
|
+
- `source` — WebAssembly binary as `Uint8Array`
|
|
226
|
+
- `options` — Optional `CompileOptions`
|
|
647
227
|
|
|
648
|
-
**
|
|
228
|
+
**Returns:** WGSL shader code as a string
|
|
649
229
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
### Types
|
|
230
|
+
**Throws:** `CompileError` on validation or compilation failure
|
|
653
231
|
|
|
654
|
-
|
|
232
|
+
### `CompileOptions`
|
|
655
233
|
|
|
656
234
|
```typescript
|
|
657
|
-
|
|
235
|
+
interface CompileOptions {
|
|
658
236
|
workgroupSize?: [number, number, number]; // Default: [64, 1, 1]
|
|
659
237
|
debug?: boolean; // Emit debug comments (default: false)
|
|
238
|
+
mathExtension?: boolean | "M0" | "M1" | "M2"; // Enable math built-ins
|
|
660
239
|
}
|
|
661
240
|
```
|
|
662
241
|
|
|
663
|
-
|
|
242
|
+
### `CompileError`
|
|
664
243
|
|
|
665
244
|
```typescript
|
|
666
|
-
|
|
245
|
+
interface CompileError {
|
|
667
246
|
type: "CompileError";
|
|
668
247
|
message: string;
|
|
669
248
|
location?: { line: number; column: number };
|
|
@@ -671,50 +250,23 @@ export interface CompileError {
|
|
|
671
250
|
}
|
|
672
251
|
```
|
|
673
252
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
Type guard to check if an error is a `CompileError`.
|
|
677
|
-
|
|
678
|
-
---
|
|
679
|
-
|
|
680
|
-
### Internal APIs
|
|
253
|
+
### `isCompileError(error)`
|
|
681
254
|
|
|
682
|
-
|
|
255
|
+
```typescript
|
|
256
|
+
function isCompileError(error: unknown): error is CompileError
|
|
257
|
+
```
|
|
683
258
|
|
|
684
|
-
|
|
685
|
-
- `phaseStackToSSA(module: WasmModule): SSAModule` — Convert to SSA
|
|
686
|
-
- `reloop(module: SSAModule): StructuredModule` — Restructure control flow
|
|
687
|
-
- `phaseMemoryLowering(module: StructuredModule): StructuredModule` — Lower memory ops
|
|
688
|
-
- `phaseWgslCodegen(module: StructuredModule, options?: CompileOptions): string` — Generate WGSL
|
|
259
|
+
Type guard for `CompileError`.
|
|
689
260
|
|
|
690
261
|
---
|
|
691
262
|
|
|
692
|
-
##
|
|
693
|
-
|
|
694
|
-
See [AGENTS.md](../../AGENTS.md) for guidelines on working with the core compiler.
|
|
263
|
+
## Related Packages
|
|
695
264
|
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
1. **Write tests first** for new features
|
|
699
|
-
2. **Run tests** with `pnpm test:core`
|
|
700
|
-
3. **Keep platform-agnostic** — no Deno-specific APIs in core logic
|
|
701
|
-
4. **Follow TypeScript strict mode** — all types must be explicit
|
|
702
|
-
5. **Document public APIs** — JSDoc for all exported functions
|
|
265
|
+
- [`@gasm-compiler/cli`](https://www.npmjs.com/package/@gasm-compiler/cli) — Command-line compiler for Wasm/AssemblyScript → WGSL
|
|
266
|
+
- [`@gasm-compiler/math-reference`](https://www.npmjs.com/package/@gasm-compiler/math-reference) — CPU-side reference implementations of Gasm math functions
|
|
703
267
|
|
|
704
268
|
---
|
|
705
269
|
|
|
706
270
|
## License
|
|
707
271
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
---
|
|
711
|
-
|
|
712
|
-
## Related Documentation
|
|
713
|
-
|
|
714
|
-
- [Gasm Specification v0.1](../../spec/gasm-v0.1.md) — GPU-executable WebAssembly spec
|
|
715
|
-
- [Instruction Set Reference](../../docs/instruction-set.md) — Detailed instruction mappings
|
|
716
|
-
- [AGENTS.md](../../AGENTS.md) — Development guidelines for agents
|
|
717
|
-
|
|
718
|
-
---
|
|
719
|
-
|
|
720
|
-
**Last Updated:** December 2025
|
|
272
|
+
See [LICENSE](./LICENSE) for details.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gasm-compiler/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Gasm Compiler — compile WebAssembly to WGSL (WebGPU Shading Language)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/mod.js",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"files": [
|
|
38
38
|
"dist",
|
|
39
|
+
"!dist/**/*.map",
|
|
39
40
|
"LICENSE",
|
|
40
41
|
"README.md"
|
|
41
42
|
],
|