[WHLSL] Enforce variable lifetimes
[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::StatementList& statementList)
376 {
377     bool once = false;
378     for (auto& statement : statementList.statements()) {
379         if (once)
380             m_out.print(";\n", m_indent);
381         once = true;
382         visit(statement);
383     }
384 }
385
386 void ASTDumper::visit(AST::Break&)
387 {
388     m_out.print("break");
389 }
390
391 void ASTDumper::visit(AST::Continue&)
392 {
393     m_out.print("continue");
394 }
395
396 void ASTDumper::visit(AST::WhileLoop& whileLoop)
397 {
398     m_out.print("while (");
399     visit(whileLoop.conditional());
400     m_out.print(")");
401     visit(whileLoop.body());
402 }
403
404 void ASTDumper::visit(AST::DoWhileLoop& doWhileLoop)
405 {
406     m_out.print("do ");
407     visit(doWhileLoop.body());
408     m_out.print(" while(");
409     visit(doWhileLoop.conditional());
410     m_out.print(")");
411 }
412
413 void ASTDumper::visit(AST::ForLoop& forLoop)
414 {
415     m_out.print("for (");
416     WTF::visit(WTF::makeVisitor([&](AST::VariableDeclarationsStatement& variableDeclarationsStatement) {
417         visit(variableDeclarationsStatement);
418     }, [&](UniqueRef<AST::Expression>& expression) {
419         visit(expression);
420     }), forLoop.initialization());
421     m_out.print("; ");
422     if (forLoop.condition())
423         visit(*forLoop.condition());
424     m_out.print("; ");
425     if (forLoop.increment())
426         visit(*forLoop.increment());
427     m_out.print(") ");
428     visit(forLoop.body());
429 }
430
431 void ASTDumper::visit(AST::Expression& expression)
432 {
433     bool skipParens = is<AST::BooleanLiteral>(expression)
434         || is<AST::FloatLiteral>(expression)
435         || is<AST::IntegerLiteral>(expression)
436         || is<AST::NullLiteral>(expression)
437         || is<AST::UnsignedIntegerLiteral>(expression)
438         || is<AST::EnumerationMemberLiteral>(expression)
439         || is<AST::CommaExpression>(expression)
440         || is<AST::VariableReference>(expression);
441
442     if (!skipParens)
443         m_out.print("(");
444     Base::visit(expression);
445     if (!skipParens)
446         m_out.print(")");
447 }
448
449 void ASTDumper::visit(AST::DotExpression& dotExpression)
450 {
451     visit(static_cast<AST::PropertyAccessExpression&>(dotExpression));
452     m_out.print(".", dotExpression.fieldName());
453 }
454
455 void ASTDumper::visit(AST::GlobalVariableReference& globalVariableReference)
456 {
457     visit(globalVariableReference.base());
458     m_out.print("=>", globalVariableReference.structField().name());
459 }
460
461 void ASTDumper::visit(AST::IndexExpression& indexExpression)
462 {
463     visit(static_cast<AST::PropertyAccessExpression&>(indexExpression));
464     m_out.print("[");
465     visit(indexExpression.indexExpression());
466     m_out.print("]");
467 }
468
469 void ASTDumper::visit(AST::PropertyAccessExpression& expression)
470 {
471     Base::visit(expression);
472 }
473
474 void ASTDumper::visit(AST::EffectfulExpressionStatement& effectfulExpressionStatement)
475 {
476     Base::visit(effectfulExpressionStatement);
477 }
478
479 void ASTDumper::visit(AST::Fallthrough&)
480 {
481     m_out.print("fallthrough");
482 }
483
484 void ASTDumper::visit(AST::IfStatement& ifStatement)
485 {
486     m_out.print("if (");
487     visit(ifStatement.conditional());
488     m_out.print(") ");
489     visit(ifStatement.body());
490     if (ifStatement.elseBody()) {
491         m_out.print(" else ");
492         visit(*ifStatement.elseBody());
493     }
494 }
495
496 void ASTDumper::visit(AST::Return& returnStatement)
497 {
498     m_out.print("return");
499     if (returnStatement.value()) {
500         m_out.print(" ");
501         visit(*returnStatement.value());
502     }
503 }
504
505 void ASTDumper::visit(AST::Trap&)
506 {
507     m_out.print("trap");
508 }
509
510 void ASTDumper::visit(AST::SwitchStatement& switchStatement)
511 {
512     m_out.print("switch (");
513     visit(switchStatement.value());
514     m_out.println(") {");
515     bool once = false;
516     for (auto& switchCase : switchStatement.switchCases()) {
517         if (once)
518             m_out.println();
519         once = true;
520         m_out.print(m_indent);
521         visit(switchCase);
522     }
523     m_out.print("\n", m_indent, "}");
524
525 }
526
527 void ASTDumper::visit(AST::SwitchCase& switchCase)
528 {
529     if (switchCase.value()) {
530         m_out.print("case ");
531         visit(*switchCase.value());
532         m_out.print(": ");
533     } else
534         m_out.print("default: ");
535     visit(switchCase.block());
536 }
537
538 void ASTDumper::visit(AST::VariableDeclarationsStatement& variableDeclarationsStatement)
539 {
540     Base::visit(variableDeclarationsStatement);
541 }
542
543 void ASTDumper::visit(AST::VariableDeclaration& variableDeclaration)
544 {
545     if (variableDeclaration.type()) {
546         visit(*variableDeclaration.type());
547         m_out.print(" ");
548     }
549
550     if (variableDeclaration.name().isEmpty())
551         m_out.print("$", RawPointer(&variableDeclaration));
552     else
553         m_out.print(variableDeclaration.name());
554
555     if (variableDeclaration.semantic())
556         visit(*variableDeclaration.semantic());
557     if (variableDeclaration.initializer()) {
558         m_out.print(" = ");
559         visit(*variableDeclaration.initializer());
560     }
561 }
562
563 void ASTDumper::visit(AST::AssignmentExpression& assignmentExpression)
564 {
565     visit(assignmentExpression.left());
566     m_out.print(" = ");
567     visit(assignmentExpression.right());
568 }
569
570 void ASTDumper::visit(AST::CallExpression& callExpression)
571 {
572     m_out.print(callExpression.name(), "(");
573     bool once = false;
574     for (auto& argument : callExpression.arguments()) {
575         if (once)
576             m_out.print(", ");
577         once = true;
578         visit(argument);
579     }
580     m_out.print(")");
581 }
582
583 void ASTDumper::visit(AST::CommaExpression& commaExpression)
584 {
585     m_out.print("(");
586     bool once = false;
587     for (auto& expression : commaExpression.list()) {
588         if (once)
589             m_out.print(", ");
590         once = true;
591         visit(expression);
592     }
593     m_out.print(")");
594 }
595
596 void ASTDumper::visit(AST::DereferenceExpression& dereferenceExpression)
597 {
598     m_out.print("*");
599     visit(dereferenceExpression.pointer());
600 }
601
602 void ASTDumper::visit(AST::LogicalExpression& logicalExpression)
603 {
604     m_out.print("(");
605     visit(logicalExpression.left());
606     switch (logicalExpression.type()) {
607     case AST::LogicalExpression::Type::And:
608         m_out.print(" && ");
609         break;
610     case AST::LogicalExpression::Type::Or:
611         m_out.print(" || ");
612         break;
613     }
614     visit(logicalExpression.right());
615     m_out.print(")");
616 }
617
618 void ASTDumper::visit(AST::LogicalNotExpression& logicalNotExpression)
619 {
620     m_out.print("!(");
621     visit(logicalNotExpression.operand());
622     m_out.print(")");
623 }
624
625 void ASTDumper::visit(AST::MakeArrayReferenceExpression& makeArrayReferenceExpression)
626 {
627     m_out.print("@");
628     visit(makeArrayReferenceExpression.leftValue());
629 }
630
631 void ASTDumper::visit(AST::MakePointerExpression& makePointerExpression)
632 {
633     m_out.print("&");
634     visit(makePointerExpression.leftValue());
635 }
636
637 void ASTDumper::visit(AST::ReadModifyWriteExpression& readModifyWriteExpression)
638 {
639     auto oldVariable = readModifyWriteExpression.oldVariableReference();
640     auto newVariable = readModifyWriteExpression.newVariableReference();
641
642     m_out.print("(");
643     visit(oldVariable.get());
644     m_out.print(" = ");
645     visit(readModifyWriteExpression.leftValue());
646     m_out.print(", ");
647
648     visit(newVariable.get());
649     m_out.print(" = ");
650     visit(readModifyWriteExpression.newValueExpression());
651     m_out.print(", ");
652
653     visit(readModifyWriteExpression.leftValue());
654     m_out.print(" = ");
655     visit(newVariable.get());
656     m_out.print(", ");
657
658     visit(readModifyWriteExpression.resultExpression());
659     m_out.print(")");
660 }
661
662 void ASTDumper::visit(AST::TernaryExpression& ternaryExpression)
663 {
664     visit(ternaryExpression.predicate());
665     m_out.print(" ? ");
666     visit(ternaryExpression.bodyExpression());
667     m_out.print(" : ");
668     visit(ternaryExpression.elseExpression());
669 }
670
671 void ASTDumper::visit(AST::VariableReference& variableReference)
672 {
673     if (variableReference.name().isEmpty())
674         m_out.print("$", RawPointer(variableReference.variable()));
675     else
676         m_out.print(variableReference.name());
677 }
678
679 } // namespace WHLSL
680
681 } // namespace WebCore
682
683 #endif