Skip to content

Commit b7cb36f

Browse files
committed
correct NaN handling
1 parent c959ad2 commit b7cb36f

3 files changed

Lines changed: 28 additions & 9 deletions

File tree

packages/typegpu/src/std/boolean.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -186,12 +186,14 @@ function cpuNot(value: unknown): boolean | AnyBooleanVecInstance {
186186

187187
if (isVecInstance(value)) {
188188
if (value.length === 2) {
189-
return vec2b(!value.x, !value.y);
189+
return vec2b(cpuNot(value.x), cpuNot(value.y));
190190
}
191191
if (value.length === 3) {
192-
return vec3b(!value.x, !value.y, !value.z);
192+
return vec3b(cpuNot(value.x), cpuNot(value.y), cpuNot(value.z));
193+
}
194+
if (value.length === 4) {
195+
return vec4b(cpuNot(value.x), cpuNot(value.y), cpuNot(value.z), cpuNot(value.w));
193196
}
194-
return vec4b(!value.x, !value.y, !value.z, !value.w);
195197
}
196198

197199
return !value;
@@ -224,10 +226,7 @@ export const not = dualImpl({
224226
normalImpl: cpuNot,
225227
codegenImpl: (_ctx, [arg]) => {
226228
if (isKnownAtComptime(arg)) {
227-
if (typeof arg.value === 'number' && isNaN(arg.value)) {
228-
return 'false';
229-
}
230-
return `${!arg.value}`;
229+
return `${cpuNot(arg.value)}`;
231230
}
232231

233232
const { dataType } = arg;

packages/typegpu/src/tgsl/wgslGenerator.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,15 @@ const unaryOpCodeToCodegen = {
173173
return snip(`!${argStr}`, bool, 'runtime');
174174
}
175175
if (wgsl.isNumericSchema(dataType)) {
176-
// no bool cast, because bool(NaN) is true in WGSL but in JS it's false
177-
return snip(`!(${argStr} != 0)`, bool, 'runtime');
176+
const resultStr = `!bool(${argStr})`;
177+
const nanGuardedStr = // abstractFloat will be resolved as comptime
178+
dataType.type === 'f32'
179+
? `(((bitcast<u32>(${argStr}) & 0x7fffffff) > 0x7f800000) || ${resultStr})`
180+
: dataType.type === 'f16'
181+
? `(((bitcast<u32>(${argStr}) & 0x7fff) > 0x7c00) || ${resultStr})`
182+
: resultStr;
183+
184+
return snip(nanGuardedStr, bool, 'runtime');
178185
}
179186

180187
return snip(false, bool, 'constant');

packages/typegpu/tests/std/boolean/not.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,19 @@ describe('not', () => {
9696
`);
9797
});
9898

99+
it('generates correct WGSL on a numeric vector comptime-known argument', () => {
100+
const f = () => {
101+
'use gpu';
102+
const v = not(d.vec4f(Infinity, -Infinity, 0, NaN));
103+
};
104+
105+
expect(tgpu.resolve([f])).toMatchInlineSnapshot(`
106+
"fn f() {
107+
var v = vec4<bool>(false, false, true, false);
108+
}"
109+
`);
110+
});
111+
99112
it('evaluates at compile time for comptime-known arguments', () => {
100113
const getN = tgpu.comptime(() => 42);
101114
const slot = tgpu.slot<{ a?: number }>({});

0 commit comments

Comments
 (0)