3eb153c2f791f3141b68a8707dd7e0c4a9e50405
[WebKit-https.git] / Source / WebCore / Modules / webgpu / WHLSL / WHLSLASTDumper.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 "WHLSLASTDumper.h"
28
29 #if ENABLE(WEBGPU)
30
31 #include "WHLSLAST.h"
32 #include "WHLSLProgram.h"
33
34 namespace WebCore {
35
36 namespace WHLSL {
37
38 void ASTDumper::visit(Program& program)
39 {
40     m_out.println();
41
42     for (size_t i = 0; i < program.nativeTypeDeclarations().size(); ++i)
43         visit(program.nativeTypeDeclarations()[i]);
44     if (program.nativeTypeDeclarations().size())
45         m_out.print("\n\n");
46
47     for (size_t i = 0; i < program.nativeFunctionDeclarations().size(); ++i)
48         visit(program.nativeFunctionDeclarations()[i]);
49     if (program.nativeFunctionDeclarations().size())
50         m_out.print("\n\n");
51
52     for (size_t i = 0; i < program.typeDefinitions().size(); ++i)
53         visit(program.typeDefinitions()[i]);
54     if (program.typeDefinitions().size())
55         m_out.print("\n\n");
56
57     for (size_t i = 0; i < program.structureDefinitions().size(); ++i)
58         visit(program.structureDefinitions()[i]);
59     if (program.structureDefinitions().size())
60         m_out.print("\n\n");
61
62     for (size_t i = 0; i < program.enumerationDefinitions().size(); ++i)
63         visit(program.enumerationDefinitions()[i]);
64     if (program.enumerationDefinitions().size())
65         m_out.print("\n\n");
66
67     for (size_t i = 0; i < program.functionDefinitions().size(); ++i)
68         visit(program.functionDefinitions()[i]);
69
70     m_out.println();
71 }
72
73 void ASTDumper::visit(AST::UnnamedType& unnamedType)
74 {
75     Base::visit(unnamedType);
76 }
77
78 void ASTDumper::visit(AST::NamedType& namedType)
79 {
80     Base::visit(namedType);
81 }
82
83 void ASTDumper::visit(AST::TypeDefinition& typeDefinition)
84 {
85     m_out.print("typedef ", typeDefinition.name(), " = ");
86     visit(typeDefinition.type());
87     m_out.println(";");
88 }
89
90 void ASTDumper::visit(AST::StructureDefinition& structureDefinition)
91 {
92     m_out.println(m_indent, "struct ", structureDefinition.name(), " {");
93     {
94         auto indent = bumpIndent();
95         for (auto& structureElement : structureDefinition.structureElements())
96             visit(structureElement);
97     }
98     m_out.println(m_indent, "}");
99     m_out.println();
100 }
101
102 void ASTDumper::visit(AST::StructureElement& structureElement)
103 {
104     m_out.print(m_indent);
105     visit(structureElement.type());
106     m_out.print(" ", structureElement.name());
107     if (structureElement.semantic())
108         visit(*structureElement.semantic());
109     m_out.println(";");
110 }
111
112 void ASTDumper::visit(AST::EnumerationDefinition& enumerationDefinition)
113 {
114     m_out.print(m_indent, "enum ");
115     visit(enumerationDefinition.type());
116     m_out.print(" {");
117
118     {
119         auto indent = bumpIndent();
120         bool once = false;
121         for (auto& enumerationMember : enumerationDefinition.enumerationMembers()) {
122             if (once)
123                 m_out.print(", ");
124             m_out.println();
125             m_out.print(m_indent);
126             visit(enumerationMember);
127         }
128     }
129
130     m_out.println();
131     m_out.println(m_indent, "}");
132     m_out.println();
133 }
134
135 void ASTDumper::visit(AST::EnumerationMember& enumerationMember)
136 {
137     m_out.print(enumerationMember.name());
138     if (enumerationMember.value()) {
139         m_out.print(" = ");
140         visit(*enumerationMember.value());
141     }
142 }
143
144 void ASTDumper::visit(AST::FunctionDefinition& functionDefinition)
145 {
146     m_out.print(m_indent);
147     visit(static_cast<AST::FunctionDeclaration&>(functionDefinition));
148     visit(functionDefinition.block());
149     m_out.print("\n\n");
150 }
151
152 void ASTDumper::visit(AST::NativeFunctionDeclaration& nativeFunctionDeclaration)
153 {
154     m_out.print(m_indent);
155     m_out.print("native ");
156     visit(static_cast<AST::FunctionDeclaration&>(nativeFunctionDeclaration));
157     m_out.println();
158 }
159
160 void ASTDumper::visit(AST::FunctionDeclaration& functionDeclaration)
161 {
162     visit(functionDeclaration.attributeBlock());
163     if (functionDeclaration.entryPointType())
164         m_out.print(AST::toString(*functionDeclaration.entryPointType()), " ");
165     visit(functionDeclaration.type());
166     m_out.print(" ", functionDeclaration.name(), "(");
167     bool once = false;
168     for (auto& parameter : functionDeclaration.parameters()) {
169         if (once)
170             m_out.print(", ");
171         once = true;
172         visit(parameter);
173     }
174     m_out.print(")");
175     if (functionDeclaration.semantic())
176         visit(*functionDeclaration.semantic());
177     m_out.print(" ");
178 }
179
180 void ASTDumper::visit(AST::NativeTypeDeclaration& nativeTypeDeclaration)
181 {
182     m_out.print(m_indent, "native typedef ");
183     m_out.print(nativeTypeDeclaration.name());
184     if (nativeTypeDeclaration.typeArguments().size()) {
185         m_out.print("<");
186         bool once = false;
187         for (auto& typeArgument : nativeTypeDeclaration.typeArguments()) {
188             if (once)
189                 m_out.print(", ");
190             once = true;
191             visit(typeArgument);
192         }
193         m_out.print(">");
194     }
195     m_out.println(";");
196 }
197
198 void ASTDumper::visit(AST::TypeReference& typeReference)
199 {
200     m_out.print(typeReference.name());
201
202     if (typeReference.typeArguments().size()) {
203         bool once = false;
204         m_out.print("<");
205         for (auto& typeArgument : typeReference.typeArguments()) {
206             if (once)
207                 m_out.print(", ");
208             once = true;
209             visit(typeArgument);
210         }
211         m_out.print(">");
212     }
213 }
214
215 void ASTDumper::visit(AST::PointerType& pointerType)
216 {
217     visit(static_cast<AST::ReferenceType&>(pointerType));
218     m_out.print("*");
219 }
220
221 void ASTDumper::visit(AST::ArrayReferenceType& arrayReferenceType)
222 {
223     visit(static_cast<AST::ReferenceType&>(arrayReferenceType));
224     m_out.print("[]");
225 }
226
227 void ASTDumper::visit(AST::ArrayType& arrayType)
228 {
229     visit(arrayType.type());
230     m_out.print("[", arrayType.numElements(), "]");
231 }
232
233 void ASTDumper::visit(AST::TypeArgument& typeArgument)
234 {
235     Base::visit(typeArgument);
236 }
237
238 void ASTDumper::visit(AST::ReferenceType& referenceType)
239 {
240     m_out.print(AST::toString(referenceType.addressSpace()), " ");
241     visit(referenceType.elementType());
242 }
243
244 void ASTDumper::visit(AST::Semantic& semantic)
245 {
246     m_out.print(" : ");
247     WTF::visit(WTF::makeVisitor([&](AST::BuiltInSemantic& builtInSemantic) {
248         visit(builtInSemantic);
249     }, [&](AST::ResourceSemantic& resourceSemantic) {
250         visit(resourceSemantic);
251     }, [&](AST::SpecializationConstantSemantic& specializationConstantSemantic) {
252         visit(specializationConstantSemantic);
253     }, [&](AST::StageInOutSemantic& stageInOutSemantic) {
254         visit(stageInOutSemantic);
255     }), semantic);
256 }
257
258 void ASTDumper::visit(AST::ConstantExpression& constantExpression)
259 {
260     Base::visit(constantExpression);
261 }
262
263 void ASTDumper::visit(AST::AttributeBlock& attributeBlock)
264 {
265     if (attributeBlock.isEmpty())
266         return;
267
268     m_out.print("[");
269     for (auto& functionAttribute : attributeBlock)
270         visit(functionAttribute);
271     m_out.print("] ");
272 }
273
274 void ASTDumper::visit(AST::BuiltInSemantic& builtInSemantic)
275 {
276     m_out.print(builtInSemantic.toString());
277 }
278
279 void ASTDumper::visit(AST::ResourceSemantic& resourceSemantic)
280 {
281     m_out.print(resourceSemantic.toString());
282 }
283
284 void ASTDumper::visit(AST::SpecializationConstantSemantic&)
285 {
286     // FIXME: Handle this when we implement it.
287 }
288
289 void ASTDumper::visit(AST::StageInOutSemantic& stageInOutSemantic)
290 {
291     m_out.print("attribute(", stageInOutSemantic.index(), ")");
292 }
293
294 void ASTDumper::visit(AST::IntegerLiteral& integerLiteral)
295 {
296     m_out.print(integerLiteral.value());
297 }
298
299 void ASTDumper::visit(AST::UnsignedIntegerLiteral& unsignedIntegerLiteral)
300 {
301     m_out.print(unsignedIntegerLiteral.value());
302 }
303
304 void ASTDumper::visit(AST::FloatLiteral& floatLiteral)
305 {
306     m_out.print(floatLiteral.value());
307 }
308
309 void ASTDumper::visit(AST::NullLiteral& nullLiteral)
310 {
311     m_out.print("null");
312     visit(nullLiteral.type());
313 }
314
315 void ASTDumper::visit(AST::BooleanLiteral& booleanLiteral)
316 {
317     if (booleanLiteral.value())
318         m_out.print("true");
319     else
320         m_out.print("false");
321 }
322
323 void ASTDumper::visit(AST::IntegerLiteralType&)
324 {
325 }
326
327 void ASTDumper::visit(AST::UnsignedIntegerLiteralType&)
328 {
329 }
330
331 void ASTDumper::visit(AST::FloatLiteralType&)
332 {
333 }
334
335 void ASTDumper::visit(AST::NullLiteralType&)
336 {
337 }
338
339 void ASTDumper::visit(AST::EnumerationMemberLiteral& enumerationMemberLiteral)
340 {
341     m_out.print(enumerationMemberLiteral.left(), ".", enumerationMemberLiteral.right());
342 }
343
344 void ASTDumper::visit(AST::FunctionAttribute& functionAttribute)
345 {
346     WTF::visit(WTF::makeVisitor([&](AST::NumThreadsFunctionAttribute& numThreadsFunctionAttribute) {
347         visit(numThreadsFunctionAttribute);
348     }), functionAttribute);
349 }
350
351 void ASTDumper::visit(AST::NumThreadsFunctionAttribute& numThreadsAttribute)
352 {
353     m_out.print("numthreads(", numThreadsAttribute.width(), ", ", numThreadsAttribute.height(), ", ", numThreadsAttribute.depth(), ")");
354 }
355
356 void ASTDumper::visit(AST::Block& block)
357 {
358     m_out.println("{");
359     {
360         auto indent = bumpIndent();
361         for (auto& statement : block.statements()) {
362             m_out.print(m_indent);
363             visit(statement);
364             m_out.println(";");
365         }
366     }
367     m_out.print(m_indent, "}");
368 }
369
370 void ASTDumper::visit(AST::Statement& statement)
371 {
372     Base::visit(statement);
373 }
374
375 void ASTDumper::visit(AST::Break&)
376 {
377     m_out.print("break");
378 }
379
380 void ASTDumper::visit(AST::Continue&)
381 {
382     m_out.print("continue");
383 }
384
385 void ASTDumper::visit(AST::WhileLoop& whileLoop)
386 {
387     m_out.print("while (");
388     visit(whileLoop.conditional());
389     m_out.print(")");
390     visit(whileLoop.body());
391 }
392
393 void ASTDumper::visit(AST::DoWhileLoop& doWhileLoop)
394 {
395     m_out.print("do ");
396     visit(doWhileLoop.body());
397     m_out.print(" while(");
398     visit(doWhileLoop.conditional());
399     m_out.print(")");
400 }
401
402 void ASTDumper::visit(AST::ForLoop& forLoop)
403 {
404     m_out.print("for (");
405     WTF::visit(WTF::makeVisitor([&](AST::VariableDeclarationsStatement& variableDeclarationsStatement) {
406         visit(variableDeclarationsStatement);
407     }, [&](UniqueRef<AST::Expression>& expression) {
408         visit(expression);
409     }), forLoop.initialization());
410     m_out.print("; ");
411     if (forLoop.condition())
412         visit(*forLoop.condition());
413     m_out.print("; ");
414     if (forLoop.increment())
415         visit(*forLoop.increment());
416     m_out.print(") ");
417     visit(forLoop.body());
418 }
419
420 void ASTDumper::visit(AST::Expression& expression)
421 {
422     bool skipParens = is<AST::BooleanLiteral>(expression)
423         || is<AST::FloatLiteral>(expression)
424         || is<AST::IntegerLiteral>(expression)
425         || is<AST::NullLiteral>(expression)
426         || is<AST::UnsignedIntegerLiteral>(expression)
427         || is<AST::EnumerationMemberLiteral>(expression)
428         || is<AST::CommaExpression>(expression)
429         || is<AST::VariableReference>(expression);
430
431     if (!skipParens)
432         m_out.print("(");
433     Base::visit(expression);
434     if (!skipParens)
435         m_out.print(")");
436 }
437
438 void ASTDumper::visit(AST::DotExpression& dotExpression)
439 {
440     visit(static_cast<AST::PropertyAccessExpression&>(dotExpression));
441     m_out.print(".", dotExpression.fieldName());
442 }
443
444 void ASTDumper::visit(AST::IndexExpression& indexExpression)
445 {
446     visit(static_cast<AST::PropertyAccessExpression&>(indexExpression));
447     m_out.print("[");
448     visit(indexExpression.indexExpression());
449     m_out.print("]");
450 }
451
452 void ASTDumper::visit(AST::PropertyAccessExpression& expression)
453 {
454     Base::visit(expression);
455 }
456
457 void ASTDumper::visit(AST::EffectfulExpressionStatement& effectfulExpressionStatement)
458 {
459     Base::visit(effectfulExpressionStatement);
460 }
461
462 void ASTDumper::visit(AST::Fallthrough&)
463 {
464     m_out.print("fallthrough");
465 }
466
467 void ASTDumper::visit(AST::IfStatement& ifStatement)
468 {
469     m_out.print("if (");
470     visit(ifStatement.conditional());
471     m_out.print(") ");
472     visit(ifStatement.body());
473     if (ifStatement.elseBody()) {
474         m_out.print(" else ");
475         visit(*ifStatement.elseBody());
476     }
477 }
478
479 void ASTDumper::visit(AST::Return& returnStatement)
480 {
481     m_out.print("return");
482     if (returnStatement.value()) {
483         m_out.print(" ");
484         visit(*returnStatement.value());
485     }
486 }
487
488 void ASTDumper::visit(AST::Trap&)
489 {
490     m_out.print("trap");
491 }
492
493 void ASTDumper::visit(AST::SwitchStatement& switchStatement)
494 {
495     m_out.print("switch (");
496     visit(switchStatement.value());
497     m_out.println(") {");
498     bool once = false;
499     for (auto& switchCase : switchStatement.switchCases()) {
500         if (once)
501             m_out.println();
502         once = true;
503         m_out.print(m_indent);
504         visit(switchCase);
505     }
506     m_out.print("\n", m_indent, "}");
507
508 }
509
510 void ASTDumper::visit(AST::SwitchCase& switchCase)
511 {
512     if (switchCase.value()) {
513         m_out.print("case ");
514         visit(*switchCase.value());
515         m_out.print(": ");
516     } else
517         m_out.print("default: ");
518     visit(switchCase.block());
519 }
520
521 void ASTDumper::visit(AST::VariableDeclarationsStatement& variableDeclarationsStatement)
522 {
523     Base::visit(variableDeclarationsStatement);
524 }
525
526 void ASTDumper::visit(AST::VariableDeclaration& variableDeclaration)
527 {
528     if (variableDeclaration.type()) {
529         visit(*variableDeclaration.type());
530         m_out.print(" ");
531     }
532     m_out.print(variableDeclaration.name());
533     if (variableDeclaration.semantic())
534         visit(*variableDeclaration.semantic());
535     if (variableDeclaration.initializer()) {
536         m_out.print(" = ");
537         visit(*variableDeclaration.initializer());
538     }
539 }
540
541 void ASTDumper::visit(AST::AssignmentExpression& assignmentExpression)
542 {
543     visit(assignmentExpression.left());
544     m_out.print(" = ");
545     visit(assignmentExpression.right());
546 }
547
548 void ASTDumper::visit(AST::CallExpression& callExpression)
549 {
550     m_out.print(callExpression.name(), "(");
551     bool once = false;
552     for (auto& argument : callExpression.arguments()) {
553         if (once)
554             m_out.print(", ");
555         once = true;
556         visit(argument);
557     }
558     m_out.print(")");
559 }
560
561 void ASTDumper::visit(AST::CommaExpression& commaExpression)
562 {
563     m_out.print("(");
564     bool once = false;
565     for (auto& expression : commaExpression.list()) {
566         if (once)
567             m_out.print(", ");
568         once = true;
569         visit(expression);
570     }
571     m_out.print(")");
572 }
573
574 void ASTDumper::visit(AST::DereferenceExpression& dereferenceExpression)
575 {
576     m_out.print("*");
577     visit(dereferenceExpression.pointer());
578 }
579
580 void ASTDumper::visit(AST::LogicalExpression& logicalExpression)
581 {
582     m_out.print("(");
583     visit(logicalExpression.left());
584     switch (logicalExpression.type()) {
585     case AST::LogicalExpression::Type::And:
586         m_out.print(" && ");
587         break;
588     case AST::LogicalExpression::Type::Or:
589         m_out.print(" || ");
590         break;
591     }
592     visit(logicalExpression.right());
593     m_out.print(")");
594 }
595
596 void ASTDumper::visit(AST::LogicalNotExpression& logicalNotExpression)
597 {
598     m_out.print("!(");
599     visit(logicalNotExpression.operand());
600     m_out.print(")");
601 }
602
603 void ASTDumper::visit(AST::MakeArrayReferenceExpression& makeArrayReferenceExpression)
604 {
605     m_out.print("@");
606     visit(makeArrayReferenceExpression.leftValue());
607 }
608
609 void ASTDumper::visit(AST::MakePointerExpression& makePointerExpression)
610 {
611     m_out.print("&");
612     visit(makePointerExpression.leftValue());
613 }
614
615 void ASTDumper::visit(AST::ReadModifyWriteExpression& readModifyWriteExpression)
616 {
617     auto oldVariable = readModifyWriteExpression.oldVariableReference();
618     auto newVariable = readModifyWriteExpression.newVariableReference();
619
620     m_out.print("(");
621     visit(oldVariable.get());
622     m_out.print(" = ");
623     visit(readModifyWriteExpression.leftValue());
624     m_out.print(", ");
625
626     visit(newVariable.get());
627     m_out.print(" = ");
628     visit(readModifyWriteExpression.newValueExpression());
629     m_out.print(", ");
630
631     visit(readModifyWriteExpression.leftValue());
632     m_out.print(" = ");
633     visit(newVariable.get());
634     m_out.print(", ");
635
636     visit(readModifyWriteExpression.resultExpression());
637     m_out.print(")");
638 }
639
640 void ASTDumper::visit(AST::TernaryExpression& ternaryExpression)
641 {
642     visit(ternaryExpression.predicate());
643     m_out.print(" ? ");
644     visit(ternaryExpression.bodyExpression());
645     m_out.print(" : ");
646     visit(ternaryExpression.elseExpression());
647 }
648
649 void ASTDumper::visit(AST::VariableReference& variableReference)
650 {
651     if (variableReference.name().isEmpty())
652         m_out.print("$", RawPointer(variableReference.variable()));
653     else
654         m_out.print(variableReference.name());
655 }
656
657 } // namespace WHLSL
658
659 } // namespace WebCore
660
661 #endif