Skip to content

Commit 133c931

Browse files
committed
fix: added FresnelC GLSL, improved GLSL compilation of loops, functions
1 parent 8212bc6 commit 133c931

6 files changed

Lines changed: 605 additions & 32 deletions

File tree

CHANGELOG.md

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
### [Unreleased]
22

3+
- **Fixed GPU compilation of `Sum`, `Product`, `Loop`, and `Function`**:
4+
These constructs no longer leak JavaScript-specific syntax (IIFEs, `let`,
5+
`while`, arrow functions, `{ re, im }` objects) into GLSL/WGSL output.
6+
`Sum`/`Product` with small constant bounds are unrolled inline; larger ranges
7+
emit native `for` loops. `Loop` emits a GPU `for` loop with `int`/`i32`
8+
index. `Function` (lambda) now throws a clear error for GPU targets.
9+
Block-level `Declare` statements infer `vec2`/`vec2f` type from subsequent
10+
complex-valued assignments.
11+
312
- **Added GLSL/WGSL compilation for `Heaviside`, `Sinc`, `FresnelC`,
4-
`BesselJ`**: These four special functions now compile to GPU shader targets.
5-
`FresnelC` uses a three-region rational Chebyshev approximation (ported from
6-
Cephes/scipy). `BesselJ` uses power series, Hankel asymptotic, and Miller's
7-
backward recurrence depending on the argument range. Both GLSL and WGSL
8-
preambles are emitted on demand.
13+
`FresnelS`, `BesselJ`**: These five special functions now compile to GPU
14+
shader targets. `FresnelC`/`FresnelS` use a three-region rational Chebyshev
15+
approximation (ported from Cephes/scipy) with a shared `_gpu_polevl` helper.
16+
`BesselJ` uses power series, Hankel asymptotic, and Miller's backward
17+
recurrence depending on the argument range. Both GLSL and WGSL preambles are
18+
emitted on demand.
919

1020
- **Fixed GLSL/WGSL block expression compilation**: Block expressions (produced
1121
by `\coloneq` / semicolon blocks) now emit valid GPU shader code instead of

src/compute-engine/compilation/base-compiler.ts

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,15 @@ export class BaseCompiler {
167167

168168
// Handle special constructs
169169
if (h === 'Function') {
170-
// Anonymous function
170+
// Dispatch to target-specific handler if available (e.g. GPU throws)
171+
const fnFn = target.functions?.(h);
172+
if (typeof fnFn === 'function')
173+
return fnFn(
174+
args,
175+
(expr) => BaseCompiler.compile(expr, target),
176+
target
177+
);
178+
// Default: JavaScript arrow function
171179
const params = args.slice(1).map((x) => (isSymbol(x) ? x.symbol : '_'));
172180
return `((${params.join(', ')}) => ${BaseCompiler.compile(
173181
args[0].canonical,
@@ -191,7 +199,16 @@ export class BaseCompiler {
191199
if (h === 'Break') return 'break';
192200
if (h === 'Continue') return 'continue';
193201

194-
if (h === 'Loop') return BaseCompiler.compileForLoop(args, target);
202+
if (h === 'Loop') {
203+
const loopFn = target.functions?.(h);
204+
if (typeof loopFn === 'function')
205+
return loopFn(
206+
args,
207+
(expr) => BaseCompiler.compile(expr, target),
208+
target
209+
);
210+
return BaseCompiler.compileForLoop(args, target);
211+
}
195212

196213
if (h === 'If') {
197214
if (args.length !== 3) throw new Error('If: wrong number of arguments');
@@ -296,17 +313,43 @@ export class BaseCompiler {
296313
return BaseCompiler.compile(args[0], target);
297314
}
298315

316+
// Infer GPU type hints for Declare+Assign pairs (complex → vec2/vec2f)
317+
const typeHints: Record<string, string | undefined> = {};
318+
if (target.declare && target.language) {
319+
const isWGSL = target.language === 'wgsl';
320+
for (const local of locals) {
321+
for (const arg of args) {
322+
if (isFunction(arg, 'Assign') && isSymbol(arg.ops[0], local)) {
323+
if (BaseCompiler.isComplexValued(arg.ops[1])) {
324+
typeHints[local] = isWGSL ? 'vec2f' : 'vec2';
325+
}
326+
break;
327+
}
328+
}
329+
}
330+
}
331+
332+
const localTarget: CompileTarget<Expression> = {
333+
...target,
334+
var: (id) => {
335+
if (locals.includes(id)) return id;
336+
return target.var(id);
337+
},
338+
};
339+
299340
const result = args
300341
.filter((a) => !isSymbol(a, 'Nothing'))
301-
.map((arg) =>
302-
BaseCompiler.compile(arg, {
303-
...target,
304-
var: (id) => {
305-
if (locals.includes(id)) return id;
306-
return target.var(id);
307-
},
308-
})
309-
)
342+
.map((arg) => {
343+
// For Declare, pass inferred type hint to the target hook
344+
if (
345+
isFunction(arg, 'Declare') &&
346+
isSymbol(arg.ops[0]) &&
347+
target.declare
348+
) {
349+
return target.declare(arg.ops[0].symbol, typeHints[arg.ops[0].symbol]);
350+
}
351+
return BaseCompiler.compile(arg, localTarget);
352+
})
310353
.filter((s) => s !== '');
311354

312355
if (result.length === 0) return '';

0 commit comments

Comments
 (0)