[WHLSL] Enforce variable lifetimes
[WebKit-https.git] / Source / WebCore / Modules / webgpu / WHLSL / WHLSLVisitor.cpp
1 /*
2  * Copyright (C) 2019 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "WHLSLVisitor.h"
28
29 #if ENABLE(WEBGPU)
30
31 #include "WHLSLAST.h"
32
33 namespace WebCore {
34
35 namespace WHLSL {
36
37 void Visitor::visit(Program& program)
38 {
39     // These visiting functions might add new global statements, so don't use foreach syntax.
40     for (size_t i = 0; i < program.typeDefinitions().size(); ++i)
41         checkErrorAndVisit(program.typeDefinitions()[i]);
42     for (size_t i = 0; i < program.structureDefinitions().size(); ++i)
43         checkErrorAndVisit(program.structureDefinitions()[i]);
44     for (size_t i = 0; i < program.enumerationDefinitions().size(); ++i)
45         checkErrorAndVisit(program.enumerationDefinitions()[i]);
46     for (size_t i = 0; i < program.functionDefinitions().size(); ++i)
47         checkErrorAndVisit(program.functionDefinitions()[i]);
48     for (size_t i = 0; i < program.nativeFunctionDeclarations().size(); ++i)
49         checkErrorAndVisit(program.nativeFunctionDeclarations()[i]);
50     for (size_t i = 0; i < program.nativeTypeDeclarations().size(); ++i)
51         checkErrorAndVisit(program.nativeTypeDeclarations()[i]);
52 }
53
54 void Visitor::visit(AST::UnnamedType& unnamedType)
55 {
56     if (is<AST::TypeReference>(unnamedType))
57         checkErrorAndVisit(downcast<AST::TypeReference>(unnamedType));
58     else if (is<AST::PointerType>(unnamedType))
59         checkErrorAndVisit(downcast<AST::PointerType>(unnamedType));
60     else if (is<AST::ArrayReferenceType>(unnamedType))
61         checkErrorAndVisit(downcast<AST::ArrayReferenceType>(unnamedType));
62     else {
63         ASSERT(is<AST::ArrayType>(unnamedType));
64         checkErrorAndVisit(downcast<AST::ArrayType>(unnamedType));
65     }
66 }
67
68 void Visitor::visit(AST::NamedType& namedType)
69 {
70     if (is<AST::TypeDefinition>(namedType))
71         checkErrorAndVisit(downcast<AST::TypeDefinition>(namedType));
72     else if (is<AST::StructureDefinition>(namedType))
73         checkErrorAndVisit(downcast<AST::StructureDefinition>(namedType));
74     else if (is<AST::EnumerationDefinition>(namedType))
75         checkErrorAndVisit(downcast<AST::EnumerationDefinition>(namedType));
76     else {
77         ASSERT(is<AST::NativeTypeDeclaration>(namedType));
78         checkErrorAndVisit(downcast<AST::NativeTypeDeclaration>(namedType));
79     }
80 }
81
82 void Visitor::visit(AST::TypeDefinition& typeDefinition)
83 {
84     checkErrorAndVisit(typeDefinition.type());
85 }
86
87 void Visitor::visit(AST::StructureDefinition& structureDefinition)
88 {
89     for (auto& structureElement : structureDefinition.structureElements())
90         checkErrorAndVisit(structureElement);
91 }
92
93 void Visitor::visit(AST::EnumerationDefinition& enumerationDefinition)
94 {
95     checkErrorAndVisit(enumerationDefinition.type());
96     for (auto& enumerationMember : enumerationDefinition.enumerationMembers())
97         checkErrorAndVisit(enumerationMember);
98 }
99
100 void Visitor::visit(AST::FunctionDefinition& functionDefinition)
101 {
102     checkErrorAndVisit(static_cast<AST::FunctionDeclaration&>(functionDefinition));
103     checkErrorAndVisit(functionDefinition.block());
104 }
105
106 void Visitor::visit(AST::NativeFunctionDeclaration& nativeFunctionDeclaration)
107 {
108     checkErrorAndVisit(static_cast<AST::FunctionDeclaration&>(nativeFunctionDeclaration));
109 }
110
111 void Visitor::visit(AST::NativeTypeDeclaration& nativeTypeDeclaration)
112 {
113     for (auto& typeArgument : nativeTypeDeclaration.typeArguments())
114         checkErrorAndVisit(typeArgument);
115 }
116
117 void Visitor::visit(AST::TypeReference& typeReference)
118 {
119     for (auto& typeArgument : typeReference.typeArguments())
120         checkErrorAndVisit(typeArgument);
121     if (typeReference.maybeResolvedType() && is<AST::TypeDefinition>(typeReference.resolvedType())) {
122         auto& typeDefinition = downcast<AST::TypeDefinition>(typeReference.resolvedType());
123         checkErrorAndVisit(typeDefinition.type());
124     }
125 }
126
127 void Visitor::visit(AST::PointerType& pointerType)
128 {
129     checkErrorAndVisit(static_cast<AST::ReferenceType&>(pointerType));
130 }
131
132 void Visitor::visit(AST::ArrayReferenceType& arrayReferenceType)
133 {
134     checkErrorAndVisit(static_cast<AST::ReferenceType&>(arrayReferenceType));
135 }
136
137 void Visitor::visit(AST::ArrayType& arrayType)
138 {
139     checkErrorAndVisit(arrayType.type());
140 }
141
142 void Visitor::visit(AST::StructureElement& structureElement)
143 {
144     checkErrorAndVisit(structureElement.type());
145     if (structureElement.semantic())
146         checkErrorAndVisit(*structureElement.semantic());
147 }
148
149 void Visitor::visit(AST::EnumerationMember& enumerationMember)
150 {
151     if (enumerationMember.value())
152         checkErrorAndVisit(*enumerationMember.value());
153 }
154
155 void Visitor::visit(AST::FunctionDeclaration& functionDeclaration)
156 {
157     checkErrorAndVisit(functionDeclaration.attributeBlock());
158     checkErrorAndVisit(functionDeclaration.type());
159     for (auto& parameter : functionDeclaration.parameters())
160         checkErrorAndVisit(parameter);
161     if (functionDeclaration.semantic())
162         checkErrorAndVisit(*functionDeclaration.semantic());
163 }
164
165 void Visitor::visit(AST::TypeArgument& typeArgument)
166 {
167     WTF::visit(WTF::makeVisitor([&](AST::ConstantExpression& constantExpression) {
168         checkErrorAndVisit(constantExpression);
169     }, [&](UniqueRef<AST::TypeReference>& typeReference) {
170         checkErrorAndVisit(typeReference);
171     }), typeArgument);
172 }
173
174 void Visitor::visit(AST::ReferenceType& referenceType)
175 {
176     checkErrorAndVisit(referenceType.elementType());
177 }
178
179 void Visitor::visit(AST::Semantic& semantic)
180 {
181     WTF::visit(WTF::makeVisitor([&](AST::BuiltInSemantic& builtInSemantic) {
182         checkErrorAndVisit(builtInSemantic);
183     }, [&](AST::ResourceSemantic& resourceSemantic) {
184         checkErrorAndVisit(resourceSemantic);
185     }, [&](AST::SpecializationConstantSemantic& specializationConstantSemantic) {
186         checkErrorAndVisit(specializationConstantSemantic);
187     }, [&](AST::StageInOutSemantic& stageInOutSemantic) {
188         checkErrorAndVisit(stageInOutSemantic);
189     }), semantic);
190 }
191
192 void Visitor::visit(AST::ConstantExpression& constantExpression)
193 {
194     constantExpression.visit(WTF::makeVisitor([&](AST::IntegerLiteral& integerLiteral) {
195         checkErrorAndVisit(integerLiteral);
196     }, [&](AST::UnsignedIntegerLiteral& unsignedIntegerLiteral) {
197         checkErrorAndVisit(unsignedIntegerLiteral);
198     }, [&](AST::FloatLiteral& floatLiteral) {
199         checkErrorAndVisit(floatLiteral);
200     }, [&](AST::NullLiteral& nullLiteral) {
201         checkErrorAndVisit(nullLiteral);
202     }, [&](AST::BooleanLiteral& booleanLiteral) {
203         checkErrorAndVisit(booleanLiteral);
204     }, [&](AST::EnumerationMemberLiteral& enumerationMemberLiteral) {
205         checkErrorAndVisit(enumerationMemberLiteral);
206     }));
207 }
208
209 void Visitor::visit(AST::AttributeBlock& attributeBlock)
210 {
211     for (auto& functionAttribute : attributeBlock)
212         checkErrorAndVisit(functionAttribute);
213 }
214
215 void Visitor::visit(AST::BuiltInSemantic&)
216 {
217 }
218
219 void Visitor::visit(AST::ResourceSemantic&)
220 {
221 }
222
223 void Visitor::visit(AST::SpecializationConstantSemantic&)
224 {
225 }
226
227 void Visitor::visit(AST::StageInOutSemantic&)
228 {
229 }
230
231 void Visitor::visit(AST::IntegerLiteral& integerLiteral)
232 {
233     checkErrorAndVisit(integerLiteral.type());
234 }
235
236 void Visitor::visit(AST::UnsignedIntegerLiteral& unsignedIntegerLiteral)
237 {
238     checkErrorAndVisit(unsignedIntegerLiteral.type());
239 }
240
241 void Visitor::visit(AST::FloatLiteral& floatLiteral)
242 {
243     checkErrorAndVisit(floatLiteral.type());
244 }
245
246 void Visitor::visit(AST::NullLiteral& nullLiteral)
247 {
248     checkErrorAndVisit(nullLiteral.type());
249 }
250
251 void Visitor::visit(AST::BooleanLiteral&)
252 {
253 }
254
255 void Visitor::visit(AST::IntegerLiteralType& integerLiteralType)
256 {
257     if (integerLiteralType.maybeResolvedType())
258         checkErrorAndVisit(integerLiteralType.resolvedType());
259     checkErrorAndVisit(integerLiteralType.preferredType());
260 }
261
262 void Visitor::visit(AST::UnsignedIntegerLiteralType& unsignedIntegerLiteralType)
263 {
264     if (unsignedIntegerLiteralType.maybeResolvedType())
265         checkErrorAndVisit(unsignedIntegerLiteralType.resolvedType());
266     checkErrorAndVisit(unsignedIntegerLiteralType.preferredType());
267 }
268
269 void Visitor::visit(AST::FloatLiteralType& floatLiteralType)
270 {
271     if (floatLiteralType.maybeResolvedType())
272         checkErrorAndVisit(floatLiteralType.resolvedType());
273     checkErrorAndVisit(floatLiteralType.preferredType());
274 }
275
276 void Visitor::visit(AST::NullLiteralType& nullLiteralType)
277 {
278     if (nullLiteralType.maybeResolvedType())
279         checkErrorAndVisit(nullLiteralType.resolvedType());
280 }
281
282 void Visitor::visit(AST::EnumerationMemberLiteral&)
283 {
284 }
285
286 void Visitor::visit(AST::FunctionAttribute& functionAttribute)
287 {
288     WTF::visit(WTF::makeVisitor([&](AST::NumThreadsFunctionAttribute& numThreadsFunctionAttribute) {
289         checkErrorAndVisit(numThreadsFunctionAttribute);
290     }), functionAttribute);
291 }
292
293 void Visitor::visit(AST::NumThreadsFunctionAttribute&)
294 {
295 }
296
297 void Visitor::visit(AST::Block& block)
298 {
299     for (auto& statement : block.statements())
300         checkErrorAndVisit(statement);
301 }
302
303 void Visitor::visit(AST::StatementList& statementList)
304 {
305     for (auto& statement : statementList.statements())
306         checkErrorAndVisit(statement);
307 }
308
309 void Visitor::visit(AST::Statement& statement)
310 {
311     if (is<AST::Block>(statement))
312         checkErrorAndVisit(downcast<AST::Block>(statement));
313     else if (is<AST::Break>(statement))
314         checkErrorAndVisit(downcast<AST::Break>(statement));
315     else if (is<AST::Continue>(statement))
316         checkErrorAndVisit(downcast<AST::Continue>(statement));
317     else if (is<AST::DoWhileLoop>(statement))
318         checkErrorAndVisit(downcast<AST::DoWhileLoop>(statement));
319     else if (is<AST::EffectfulExpressionStatement>(statement))
320         checkErrorAndVisit(downcast<AST::EffectfulExpressionStatement>(statement));
321     else if (is<AST::Fallthrough>(statement))
322         checkErrorAndVisit(downcast<AST::Fallthrough>(statement));
323     else if (is<AST::ForLoop>(statement))
324         checkErrorAndVisit(downcast<AST::ForLoop>(statement));
325     else if (is<AST::IfStatement>(statement))
326         checkErrorAndVisit(downcast<AST::IfStatement>(statement));
327     else if (is<AST::Return>(statement))
328         checkErrorAndVisit(downcast<AST::Return>(statement));
329     else if (is<AST::StatementList>(statement))
330         checkErrorAndVisit(downcast<AST::StatementList>(statement));
331     else if (is<AST::SwitchCase>(statement))
332         checkErrorAndVisit(downcast<AST::SwitchCase>(statement));
333     else if (is<AST::SwitchStatement>(statement))
334         checkErrorAndVisit(downcast<AST::SwitchStatement>(statement));
335     else if (is<AST::Trap>(statement))
336         checkErrorAndVisit(downcast<AST::Trap>(statement));
337     else if (is<AST::VariableDeclarationsStatement>(statement))
338         checkErrorAndVisit(downcast<AST::VariableDeclarationsStatement>(statement));
339     else {
340         ASSERT(is<AST::WhileLoop>(statement));
341         checkErrorAndVisit(downcast<AST::WhileLoop>(statement));
342     }
343 }
344
345 void Visitor::visit(AST::Break&)
346 {
347 }
348
349 void Visitor::visit(AST::Continue&)
350 {
351 }
352
353 void Visitor::visit(AST::DoWhileLoop& doWhileLoop)
354 {
355     checkErrorAndVisit(doWhileLoop.body());
356     checkErrorAndVisit(doWhileLoop.conditional());
357 }
358
359 void Visitor::visit(AST::Expression& expression)
360 {
361     if (is<AST::AssignmentExpression>(expression))
362         checkErrorAndVisit(downcast<AST::AssignmentExpression>(expression));
363     else if (is<AST::BooleanLiteral>(expression))
364         checkErrorAndVisit(downcast<AST::BooleanLiteral>(expression));
365     else if (is<AST::CallExpression>(expression))
366         checkErrorAndVisit(downcast<AST::CallExpression>(expression));
367     else if (is<AST::CommaExpression>(expression))
368         checkErrorAndVisit(downcast<AST::CommaExpression>(expression));
369     else if (is<AST::DereferenceExpression>(expression))
370         checkErrorAndVisit(downcast<AST::DereferenceExpression>(expression));
371     else if (is<AST::FloatLiteral>(expression))
372         checkErrorAndVisit(downcast<AST::FloatLiteral>(expression));
373     else if (is<AST::IntegerLiteral>(expression))
374         checkErrorAndVisit(downcast<AST::IntegerLiteral>(expression));
375     else if (is<AST::LogicalExpression>(expression))
376         checkErrorAndVisit(downcast<AST::LogicalExpression>(expression));
377     else if (is<AST::LogicalNotExpression>(expression))
378         checkErrorAndVisit(downcast<AST::LogicalNotExpression>(expression));
379     else if (is<AST::MakeArrayReferenceExpression>(expression))
380         checkErrorAndVisit(downcast<AST::MakeArrayReferenceExpression>(expression));
381     else if (is<AST::MakePointerExpression>(expression))
382         checkErrorAndVisit(downcast<AST::MakePointerExpression>(expression));
383     else if (is<AST::NullLiteral>(expression))
384         checkErrorAndVisit(downcast<AST::NullLiteral>(expression));
385     else if (is<AST::DotExpression>(expression))
386         checkErrorAndVisit(downcast<AST::DotExpression>(expression));
387     else if (is<AST::GlobalVariableReference>(expression))
388         checkErrorAndVisit(downcast<AST::GlobalVariableReference>(expression));
389     else if (is<AST::IndexExpression>(expression))
390         checkErrorAndVisit(downcast<AST::IndexExpression>(expression));
391     else if (is<AST::ReadModifyWriteExpression>(expression))
392         checkErrorAndVisit(downcast<AST::ReadModifyWriteExpression>(expression));
393     else if (is<AST::TernaryExpression>(expression))
394         checkErrorAndVisit(downcast<AST::TernaryExpression>(expression));
395     else if (is<AST::UnsignedIntegerLiteral>(expression))
396         checkErrorAndVisit(downcast<AST::UnsignedIntegerLiteral>(expression));
397     else if (is<AST::EnumerationMemberLiteral>(expression))
398         checkErrorAndVisit(downcast<AST::EnumerationMemberLiteral>(expression));
399     else {
400         ASSERT(is<AST::VariableReference>(expression));
401         checkErrorAndVisit(downcast<AST::VariableReference>(expression));
402     }
403 }
404
405 void Visitor::visit(AST::DotExpression& dotExpression)
406 {
407     checkErrorAndVisit(static_cast<AST::PropertyAccessExpression&>(dotExpression));
408 }
409
410 void Visitor::visit(AST::GlobalVariableReference& globalVariableReference)
411 {
412     checkErrorAndVisit(globalVariableReference.base());
413 }
414
415 void Visitor::visit(AST::IndexExpression& indexExpression)
416 {
417     checkErrorAndVisit(indexExpression.indexExpression());
418     checkErrorAndVisit(static_cast<AST::PropertyAccessExpression&>(indexExpression));
419 }
420
421 void Visitor::visit(AST::PropertyAccessExpression& expression)
422 {
423     checkErrorAndVisit(expression.base());
424 }
425
426 void Visitor::visit(AST::EffectfulExpressionStatement& effectfulExpressionStatement)
427 {
428     checkErrorAndVisit(effectfulExpressionStatement.effectfulExpression());
429 }
430
431 void Visitor::visit(AST::Fallthrough&)
432 {
433 }
434
435 void Visitor::visit(AST::ForLoop& forLoop)
436 {
437     WTF::visit(WTF::makeVisitor([&](AST::VariableDeclarationsStatement& variableDeclarationsStatement) {
438         checkErrorAndVisit(variableDeclarationsStatement);
439     }, [&](UniqueRef<AST::Expression>& expression) {
440         checkErrorAndVisit(expression);
441     }), forLoop.initialization());
442     if (forLoop.condition())
443         checkErrorAndVisit(*forLoop.condition());
444     if (forLoop.increment())
445         checkErrorAndVisit(*forLoop.increment());
446     checkErrorAndVisit(forLoop.body());
447 }
448
449 void Visitor::visit(AST::IfStatement& ifStatement)
450 {
451     checkErrorAndVisit(ifStatement.conditional());
452     checkErrorAndVisit(ifStatement.body());
453     if (ifStatement.elseBody())
454         checkErrorAndVisit(*ifStatement.elseBody());
455 }
456
457 void Visitor::visit(AST::Return& returnStatement)
458 {
459     if (returnStatement.value())
460         checkErrorAndVisit(*returnStatement.value());
461 }
462
463 void Visitor::visit(AST::SwitchCase& switchCase)
464 {
465     if (switchCase.value())
466         checkErrorAndVisit(*switchCase.value());
467     checkErrorAndVisit(switchCase.block());
468 }
469
470 void Visitor::visit(AST::SwitchStatement& switchStatement)
471 {
472     checkErrorAndVisit(switchStatement.value());
473     for (auto& switchCase : switchStatement.switchCases())
474         checkErrorAndVisit(switchCase);
475 }
476
477 void Visitor::visit(AST::Trap&)
478 {
479 }
480
481 void Visitor::visit(AST::VariableDeclarationsStatement& variableDeclarationsStatement)
482 {
483     for (auto& variableDeclaration : variableDeclarationsStatement.variableDeclarations())
484         checkErrorAndVisit(variableDeclaration.get());
485 }
486
487 void Visitor::visit(AST::WhileLoop& whileLoop)
488 {
489     checkErrorAndVisit(whileLoop.conditional());
490     checkErrorAndVisit(whileLoop.body());
491 }
492
493 void Visitor::visit(AST::VariableDeclaration& variableDeclaration)
494 {
495     if (variableDeclaration.type())
496         checkErrorAndVisit(*variableDeclaration.type());
497     if (variableDeclaration.semantic())
498         checkErrorAndVisit(*variableDeclaration.semantic());
499     if (variableDeclaration.initializer())
500         checkErrorAndVisit(*variableDeclaration.initializer());
501 }
502
503 void Visitor::visit(AST::AssignmentExpression& assignmentExpression)
504 {
505     checkErrorAndVisit(assignmentExpression.left());
506     checkErrorAndVisit(assignmentExpression.right());
507 }
508
509 void Visitor::visit(AST::CallExpression& callExpression)
510 {
511     for (auto& argument : callExpression.arguments())
512         checkErrorAndVisit(argument);
513     if (callExpression.castReturnType())
514         checkErrorAndVisit(*callExpression.castReturnType());
515 }
516
517 void Visitor::visit(AST::CommaExpression& commaExpression)
518 {
519     for (auto& expression : commaExpression.list())
520         checkErrorAndVisit(expression);
521 }
522
523 void Visitor::visit(AST::DereferenceExpression& dereferenceExpression)
524 {
525     checkErrorAndVisit(dereferenceExpression.pointer());
526 }
527
528 void Visitor::visit(AST::LogicalExpression& logicalExpression)
529 {
530     checkErrorAndVisit(logicalExpression.left());
531     checkErrorAndVisit(logicalExpression.right());
532 }
533
534 void Visitor::visit(AST::LogicalNotExpression& logicalNotExpression)
535 {
536     checkErrorAndVisit(logicalNotExpression.operand());
537 }
538
539 void Visitor::visit(AST::MakeArrayReferenceExpression& makeArrayReferenceExpression)
540 {
541     checkErrorAndVisit(makeArrayReferenceExpression.leftValue());
542 }
543
544 void Visitor::visit(AST::MakePointerExpression& makePointerExpression)
545 {
546     checkErrorAndVisit(makePointerExpression.leftValue());
547 }
548
549 void Visitor::visit(AST::ReadModifyWriteExpression& readModifyWriteExpression)
550 {
551     checkErrorAndVisit(readModifyWriteExpression.leftValue());
552     checkErrorAndVisit(readModifyWriteExpression.oldValue());
553     checkErrorAndVisit(readModifyWriteExpression.newValue());
554     checkErrorAndVisit(readModifyWriteExpression.newValueExpression());
555     checkErrorAndVisit(readModifyWriteExpression.resultExpression());
556 }
557
558 void Visitor::visit(AST::TernaryExpression& ternaryExpression)
559 {
560     checkErrorAndVisit(ternaryExpression.predicate());
561     checkErrorAndVisit(ternaryExpression.bodyExpression());
562     checkErrorAndVisit(ternaryExpression.elseExpression());
563 }
564
565 void Visitor::visit(AST::VariableReference&)
566 {
567 }
568
569 } // namespace WHLSL
570
571 } // namespace WebCore
572
573 #endif // ENABLE(WEBGPU)