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 "WHLSLFunctionWriter.h"
28
29#if ENABLE(WEBGPU)
30
31#include "NotImplemented.h"
32#include "WHLSLArrayReferenceType.h"
33#include "WHLSLArrayType.h"
34#include "WHLSLAssignmentExpression.h"
35#include "WHLSLBooleanLiteral.h"
36#include "WHLSLBuiltInSemantic.h"
37#include "WHLSLCallExpression.h"
38#include "WHLSLCommaExpression.h"
39#include "WHLSLDereferenceExpression.h"
40#include "WHLSLDoWhileLoop.h"
41#include "WHLSLEffectfulExpressionStatement.h"
42#include "WHLSLEntryPointScaffolding.h"
43#include "WHLSLEntryPointType.h"
44#include "WHLSLFloatLiteral.h"
45#include "WHLSLForLoop.h"
46#include "WHLSLFunctionDeclaration.h"
47#include "WHLSLFunctionDefinition.h"
48#include "WHLSLIfStatement.h"
49#include "WHLSLIntegerLiteral.h"
50#include "WHLSLLogicalExpression.h"
51#include "WHLSLLogicalNotExpression.h"
52#include "WHLSLMakeArrayReferenceExpression.h"
53#include "WHLSLMakePointerExpression.h"
54#include "WHLSLNativeFunctionDeclaration.h"
55#include "WHLSLNativeFunctionWriter.h"
56#include "WHLSLNativeTypeDeclaration.h"
57#include "WHLSLPointerType.h"
58#include "WHLSLProgram.h"
59#include "WHLSLReturn.h"
60#include "WHLSLSwitchCase.h"
61#include "WHLSLSwitchStatement.h"
62#include "WHLSLTernaryExpression.h"
63#include "WHLSLTypeNamer.h"
64#include "WHLSLUnsignedIntegerLiteral.h"
65#include "WHLSLVariableDeclaration.h"
66#include "WHLSLVariableDeclarationsStatement.h"
67#include "WHLSLVariableReference.h"
68#include "WHLSLVisitor.h"
69#include "WHLSLWhileLoop.h"
70#include <wtf/HashMap.h>
71#include <wtf/text/StringBuilder.h>
72
73namespace WebCore {
74
75namespace WHLSL {
76
77namespace Metal {
78
79class FunctionDeclarationWriter : public Visitor {
80public:
81 FunctionDeclarationWriter(TypeNamer& typeNamer, HashMap<AST::FunctionDeclaration*, String>& functionMapping)
82 : m_typeNamer(typeNamer)
83 , m_functionMapping(functionMapping)
84 {
85 }
86
87 virtual ~FunctionDeclarationWriter() = default;
88
89 String toString() { return m_stringBuilder.toString(); }
90
91 void visit(AST::FunctionDeclaration&) override;
92
93private:
94 TypeNamer& m_typeNamer;
95 HashMap<AST::FunctionDeclaration*, String>& m_functionMapping;
96 StringBuilder m_stringBuilder;
97};
98
99void FunctionDeclarationWriter::visit(AST::FunctionDeclaration& functionDeclaration)
100{
101 if (functionDeclaration.entryPointType())
102 return;
103
104 auto iterator = m_functionMapping.find(&functionDeclaration);
105 ASSERT(iterator != m_functionMapping.end());
106 m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(functionDeclaration.type()), ' ', iterator->value, '('));
107 for (size_t i = 0; i < functionDeclaration.parameters().size(); ++i) {
108 if (i)
109 m_stringBuilder.append(", ");
110 m_stringBuilder.append(m_typeNamer.mangledNameForType(*functionDeclaration.parameters()[i].type()));
111 }
112 m_stringBuilder.append(");\n");
113}
114
115class FunctionDefinitionWriter : public Visitor {
116public:
117 FunctionDefinitionWriter(Intrinsics& intrinsics, TypeNamer& typeNamer, HashMap<AST::FunctionDeclaration*, String>& functionMapping, Layout& layout)
118 : m_intrinsics(intrinsics)
119 , m_typeNamer(typeNamer)
120 , m_functionMapping(functionMapping)
121 , m_layout(layout)
122 {
123 }
124
125 virtual ~FunctionDefinitionWriter() = default;
126
127 String toString() { return m_stringBuilder.toString(); }
128
129 void visit(AST::NativeFunctionDeclaration&) override;
130 void visit(AST::FunctionDefinition&) override;
131
132protected:
133 virtual std::unique_ptr<EntryPointScaffolding> createEntryPointScaffolding(AST::FunctionDefinition&) = 0;
134
135 void visit(AST::FunctionDeclaration&) override;
136 void visit(AST::Statement&) override;
137 void visit(AST::Block&) override;
138 void visit(AST::Break&) override;
139 void visit(AST::Continue&) override;
140 void visit(AST::DoWhileLoop&) override;
141 void visit(AST::EffectfulExpressionStatement&) override;
142 void visit(AST::Fallthrough&) override;
143 void visit(AST::ForLoop&) override;
144 void visit(AST::IfStatement&) override;
145 void visit(AST::Return&) override;
146 void visit(AST::SwitchStatement&) override;
147 void visit(AST::SwitchCase&) override;
148 void visit(AST::Trap&) override;
149 void visit(AST::VariableDeclarationsStatement&) override;
150 void visit(AST::WhileLoop&) override;
151 void visit(AST::IntegerLiteral&) override;
152 void visit(AST::UnsignedIntegerLiteral&) override;
153 void visit(AST::FloatLiteral&) override;
154 void visit(AST::NullLiteral&) override;
155 void visit(AST::BooleanLiteral&) override;
156 void visit(AST::EnumerationMemberLiteral&) override;
157 void visit(AST::Expression&) override;
158 void visit(AST::DotExpression&) override;
159 void visit(AST::IndexExpression&) override;
160 void visit(AST::PropertyAccessExpression&) override;
161 void visit(AST::VariableDeclaration&) override;
162 void visit(AST::AssignmentExpression&) override;
163 void visit(AST::CallExpression&) override;
164 void visit(AST::CommaExpression&) override;
165 void visit(AST::DereferenceExpression&) override;
166 void visit(AST::LogicalExpression&) override;
167 void visit(AST::LogicalNotExpression&) override;
168 void visit(AST::MakeArrayReferenceExpression&) override;
169 void visit(AST::MakePointerExpression&) override;
170 void visit(AST::ReadModifyWriteExpression&) override;
171 void visit(AST::TernaryExpression&) override;
172 void visit(AST::VariableReference&) override;
173
174 String constantExpressionString(AST::ConstantExpression&);
175
176 String generateNextVariableName()
177 {
178 return makeString("variable", m_variableCount++);
179 }
180
181 Intrinsics& m_intrinsics;
182 TypeNamer& m_typeNamer;
183 HashMap<AST::FunctionDeclaration*, String>& m_functionMapping;
184 HashMap<AST::VariableDeclaration*, String> m_variableMapping;
185 StringBuilder m_stringBuilder;
186 Vector<String> m_stack;
187 std::unique_ptr<EntryPointScaffolding> m_entryPointScaffolding;
188 Layout& m_layout;
189 unsigned m_variableCount { 0 };
190};
191
192void FunctionDefinitionWriter::visit(AST::NativeFunctionDeclaration& nativeFunctionDeclaration)
193{
194 auto iterator = m_functionMapping.find(&nativeFunctionDeclaration);
195 ASSERT(iterator != m_functionMapping.end());
196 m_stringBuilder.append(writeNativeFunction(nativeFunctionDeclaration, iterator->value, m_intrinsics, m_typeNamer));
197}
198
199void FunctionDefinitionWriter::visit(AST::FunctionDefinition& functionDefinition)
200{
201 auto iterator = m_functionMapping.find(&functionDefinition);
202 ASSERT(iterator != m_functionMapping.end());
203 if (functionDefinition.entryPointType()) {
204 auto entryPointScaffolding = createEntryPointScaffolding(functionDefinition);
205 if (!entryPointScaffolding)
206 return;
207 m_entryPointScaffolding = WTFMove(entryPointScaffolding);
208 m_stringBuilder.append(m_entryPointScaffolding->helperTypes());
209 m_stringBuilder.append('\n');
210 m_stringBuilder.append(makeString(m_entryPointScaffolding->signature(iterator->value), " {\n"));
211 m_stringBuilder.append(m_entryPointScaffolding->unpack());
212 for (size_t i = 0; i < functionDefinition.parameters().size(); ++i) {
213 auto addResult = m_variableMapping.add(&functionDefinition.parameters()[i], m_entryPointScaffolding->parameterVariables()[i]);
214 ASSERT_UNUSED(addResult, addResult.isNewEntry);
215 }
216 checkErrorAndVisit(functionDefinition.block());
217 ASSERT(m_stack.isEmpty());
218 m_stringBuilder.append("}\n");
219 m_entryPointScaffolding = nullptr;
220 } else {
221 ASSERT(m_entryPointScaffolding == nullptr);
222 m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(functionDefinition.type()), ' ', iterator->value, '('));
223 for (size_t i = 0; i < functionDefinition.parameters().size(); ++i) {
224 auto& parameter = functionDefinition.parameters()[i];
225 if (i)
226 m_stringBuilder.append(", ");
227 auto parameterName = generateNextVariableName();
228 auto addResult = m_variableMapping.add(&parameter, parameterName);
229 ASSERT_UNUSED(addResult, addResult.isNewEntry);
230 m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*parameter.type()), ' ', parameterName));
231 }
232 m_stringBuilder.append(") {\n");
233 checkErrorAndVisit(functionDefinition.block());
234 ASSERT(m_stack.isEmpty());
235 m_stringBuilder.append("}\n");
236 }
237}
238
239void FunctionDefinitionWriter::visit(AST::FunctionDeclaration&)
240{
241 ASSERT_NOT_REACHED();
242}
243
244void FunctionDefinitionWriter::visit(AST::Statement& statement)
245{
246 Visitor::visit(statement);
247}
248
249void FunctionDefinitionWriter::visit(AST::Block& block)
250{
251 m_stringBuilder.append("{\n");
252 for (auto& statement : block.statements())
253 checkErrorAndVisit(statement);
254 m_stringBuilder.append("}\n");
255}
256
257void FunctionDefinitionWriter::visit(AST::Break&)
258{
259 m_stringBuilder.append("break;\n");
260}
261
262void FunctionDefinitionWriter::visit(AST::Continue&)
263{
264 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195808 Figure out which loop we're in, and run the increment code
265 notImplemented();
266}
267
268void FunctionDefinitionWriter::visit(AST::DoWhileLoop& doWhileLoop)
269{
270 m_stringBuilder.append("do {\n");
271 checkErrorAndVisit(doWhileLoop.body());
272 checkErrorAndVisit(doWhileLoop.conditional());
273 m_stringBuilder.append(makeString("if (!", m_stack.takeLast(), ") break;\n"));
274 m_stringBuilder.append(makeString("} while(true);\n"));
275}
276
277void FunctionDefinitionWriter::visit(AST::EffectfulExpressionStatement& effectfulExpressionStatement)
278{
279 checkErrorAndVisit(effectfulExpressionStatement.effectfulExpression());
280 m_stack.takeLast(); // The statement is already effectful, so we don't need to do anything with the result.
281}
282
283void FunctionDefinitionWriter::visit(AST::Fallthrough&)
284{
285 m_stringBuilder.append("[[clang::fallthrough]];\n"); // FIXME: Make sure this is okay. Alternatively, we could do nothing and just return here instead.
286}
287
288void FunctionDefinitionWriter::visit(AST::ForLoop& forLoop)
289{
290 WTF::visit(WTF::makeVisitor([&](AST::VariableDeclarationsStatement& variableDeclarationsStatement) {
291 checkErrorAndVisit(variableDeclarationsStatement);
292 }, [&](UniqueRef<AST::Expression>& expression) {
293 checkErrorAndVisit(expression);
294 m_stack.takeLast(); // We don't need to do anything with the result.
295 }), forLoop.initialization());
296
297 m_stringBuilder.append("for ( ; ; ) {\n");
298 if (forLoop.condition()) {
299 checkErrorAndVisit(*forLoop.condition());
300 m_stringBuilder.append(makeString("if (!", m_stack.takeLast(), ") break;\n"));
301 }
302 checkErrorAndVisit(forLoop.body());
303 if (forLoop.increment()) {
304 checkErrorAndVisit(*forLoop.increment());
305 m_stack.takeLast();
306 }
307 m_stringBuilder.append("}\n");
308}
309
310void FunctionDefinitionWriter::visit(AST::IfStatement& ifStatement)
311{
312 checkErrorAndVisit(ifStatement.conditional());
313 m_stringBuilder.append(makeString("if (", m_stack.takeLast(), ") {\n"));
314 checkErrorAndVisit(ifStatement.body());
315 if (ifStatement.elseBody()) {
316 m_stringBuilder.append("} else {\n");
317 checkErrorAndVisit(*ifStatement.elseBody());
318 }
319 m_stringBuilder.append("}\n");
320}
321
322void FunctionDefinitionWriter::visit(AST::Return& returnStatement)
323{
324 if (returnStatement.value()) {
325 checkErrorAndVisit(*returnStatement.value());
326 if (m_entryPointScaffolding) {
327 auto variableName = generateNextVariableName();
328 m_stringBuilder.append(m_entryPointScaffolding->pack(m_stack.takeLast(), variableName));
329 m_stringBuilder.append(makeString("return ", variableName, ";\n"));
330 } else
331 m_stringBuilder.append(makeString("return ", m_stack.takeLast(), ";\n"));
332 } else
333 m_stringBuilder.append("return;\n");
334}
335
336void FunctionDefinitionWriter::visit(AST::SwitchStatement& switchStatement)
337{
338 checkErrorAndVisit(switchStatement.value());
339
340 m_stringBuilder.append(makeString("switch (", m_stack.takeLast(), ") {"));
341 for (auto& switchCase : switchStatement.switchCases())
342 checkErrorAndVisit(switchCase);
343 m_stringBuilder.append("}\n");
344}
345
346void FunctionDefinitionWriter::visit(AST::SwitchCase& switchCase)
347{
348 if (switchCase.value())
349 m_stringBuilder.append(makeString("case ", constantExpressionString(*switchCase.value()), ":\n"));
350 else
351 m_stringBuilder.append("default:\n");
352 checkErrorAndVisit(switchCase.block());
353 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195812 Figure out whether we need to break or fallthrough.
354 notImplemented();
355}
356
357void FunctionDefinitionWriter::visit(AST::Trap&)
358{
359 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195811 Implement this
360 notImplemented();
361}
362
363void FunctionDefinitionWriter::visit(AST::VariableDeclarationsStatement& variableDeclarationsStatement)
364{
365 Visitor::visit(variableDeclarationsStatement);
366}
367
368void FunctionDefinitionWriter::visit(AST::WhileLoop& whileLoop)
369{
370 m_stringBuilder.append(makeString("while (true) {\n"));
371 checkErrorAndVisit(whileLoop.conditional());
372 m_stringBuilder.append(makeString("if (!", m_stack.takeLast(), ") break;\n"));
373 checkErrorAndVisit(whileLoop.body());
374 m_stringBuilder.append("}\n");
375}
376
377void FunctionDefinitionWriter::visit(AST::IntegerLiteral& integerLiteral)
378{
379 ASSERT(integerLiteral.resolvedType());
380 auto variableName = generateNextVariableName();
381 auto mangledTypeName = m_typeNamer.mangledNameForType(*integerLiteral.resolvedType());
382 m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", integerLiteral.value(), ");\n"));
383 m_stack.append(variableName);
384}
385
386void FunctionDefinitionWriter::visit(AST::UnsignedIntegerLiteral& unsignedIntegerLiteral)
387{
388 ASSERT(unsignedIntegerLiteral.resolvedType());
389 auto variableName = generateNextVariableName();
390 auto mangledTypeName = m_typeNamer.mangledNameForType(*unsignedIntegerLiteral.resolvedType());
391 m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", unsignedIntegerLiteral.value(), ");\n"));
392 m_stack.append(variableName);
393}
394
395void FunctionDefinitionWriter::visit(AST::FloatLiteral& floatLiteral)
396{
397 ASSERT(floatLiteral.resolvedType());
398 auto variableName = generateNextVariableName();
399 auto mangledTypeName = m_typeNamer.mangledNameForType(*floatLiteral.resolvedType());
400 m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", floatLiteral.value(), ");\n"));
401 m_stack.append(variableName);
402}
403
404void FunctionDefinitionWriter::visit(AST::NullLiteral& nullLiteral)
405{
406 ASSERT(nullLiteral.resolvedType());
407 auto& unifyNode = nullLiteral.resolvedType()->unifyNode();
408 ASSERT(is<AST::UnnamedType>(unifyNode));
409 auto& unnamedType = downcast<AST::UnnamedType>(unifyNode);
410 bool isArrayReferenceType = is<AST::ArrayReferenceType>(unnamedType);
411
412 auto variableName = generateNextVariableName();
413 m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*nullLiteral.resolvedType()), ' ', variableName, " = "));
414 if (isArrayReferenceType)
415 m_stringBuilder.append("{ nullptr, 0 }");
416 else
417 m_stringBuilder.append("nullptr");
418 m_stringBuilder.append(";\n");
419 m_stack.append(variableName);
420}
421
422void FunctionDefinitionWriter::visit(AST::BooleanLiteral& booleanLiteral)
423{
424 ASSERT(booleanLiteral.resolvedType());
425 auto variableName = generateNextVariableName();
426 auto mangledTypeName = m_typeNamer.mangledNameForType(*booleanLiteral.resolvedType());
427 m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", booleanLiteral.value() ? "true" : "false", ");\n"));
428 m_stack.append(variableName);
429}
430
431void FunctionDefinitionWriter::visit(AST::EnumerationMemberLiteral& enumerationMemberLiteral)
432{
433 ASSERT(enumerationMemberLiteral.resolvedType());
434 ASSERT(enumerationMemberLiteral.enumerationDefinition());
435 ASSERT(enumerationMemberLiteral.enumerationDefinition());
436 auto variableName = generateNextVariableName();
437 auto mangledTypeName = m_typeNamer.mangledNameForType(*enumerationMemberLiteral.resolvedType());
438 m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = ", mangledTypeName, '.', m_typeNamer.mangledNameForEnumerationMember(*enumerationMemberLiteral.enumerationMember()), ";\n"));
439 m_stack.append(variableName);
440}
441
442void FunctionDefinitionWriter::visit(AST::Expression& expression)
443{
444 Visitor::visit(expression);
445}
446
447void FunctionDefinitionWriter::visit(AST::DotExpression&)
448{
449 // This should be lowered already.
450 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195788 Replace this with ASSERT_NOT_REACHED().
451 notImplemented();
452 m_stack.append("dummy");
453}
454
455void FunctionDefinitionWriter::visit(AST::IndexExpression&)
456{
457 // This should be lowered already.
458 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195788 Replace this with ASSERT_NOT_REACHED().
459 notImplemented();
460 m_stack.append("dummy");
461}
462
463void FunctionDefinitionWriter::visit(AST::PropertyAccessExpression&)
464{
465 // This should be lowered already.
466 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195788 Replace this with ASSERT_NOT_REACHED().
467 notImplemented();
468 m_stack.append("dummy");
469}
470
471void FunctionDefinitionWriter::visit(AST::VariableDeclaration& variableDeclaration)
472{
473 ASSERT(variableDeclaration.type());
474 auto variableName = generateNextVariableName();
475 auto addResult = m_variableMapping.add(&variableDeclaration, variableName);
476 ASSERT_UNUSED(addResult, addResult.isNewEntry);
477 // FIXME: Implement qualifiers.
478 if (variableDeclaration.initializer()) {
479 checkErrorAndVisit(*variableDeclaration.initializer());
480 m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*variableDeclaration.type()), ' ', variableName, " = ", m_stack.takeLast(), ";\n"));
481 } else {
482 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195771 Zero-fill the variable.
483 m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*variableDeclaration.type()), ' ', variableName, ";\n"));
484 }
485}
486
487void FunctionDefinitionWriter::visit(AST::AssignmentExpression& assignmentExpression)
488{
489 checkErrorAndVisit(assignmentExpression.left());
490 auto leftName = m_stack.takeLast();
491 checkErrorAndVisit(assignmentExpression.right());
492 auto rightName = m_stack.takeLast();
493 m_stringBuilder.append(makeString(leftName, " = ", rightName, ";\n"));
494 m_stack.append(leftName);
495}
496
497void FunctionDefinitionWriter::visit(AST::CallExpression& callExpression)
498{
499 Vector<String> argumentNames;
500 for (auto& argument : callExpression.arguments()) {
501 checkErrorAndVisit(argument);
502 argumentNames.append(m_stack.takeLast());
503 }
504 ASSERT(callExpression.resolvedType());
505 ASSERT(callExpression.function());
506 auto iterator = m_functionMapping.find(callExpression.function());
507 ASSERT(iterator != m_functionMapping.end());
508 auto variableName = generateNextVariableName();
509 m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*callExpression.resolvedType()), ' ', variableName, " = ", iterator->value, '('));
510 for (size_t i = 0; i < argumentNames.size(); ++i) {
511 if (i)
512 m_stringBuilder.append(", ");
513 m_stringBuilder.append(argumentNames[i]);
514 }
515 m_stringBuilder.append(");\n");
516 m_stack.append(variableName);
517}
518
519void FunctionDefinitionWriter::visit(AST::CommaExpression& commaExpression)
520{
521 String result;
522 for (auto& expression : commaExpression.list()) {
523 checkErrorAndVisit(expression);
524 result = m_stack.takeLast();
525 }
526 m_stack.append(result);
527}
528
529void FunctionDefinitionWriter::visit(AST::DereferenceExpression& dereferenceExpression)
530{
531 checkErrorAndVisit(dereferenceExpression.pointer());
532 auto right = m_stack.takeLast();
533 ASSERT(dereferenceExpression.resolvedType());
534 auto variableName = generateNextVariableName();
535 m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*dereferenceExpression.resolvedType()), ' ', variableName, " = *", right, ";\n"));
536 m_stack.append(variableName);
537}
538
539void FunctionDefinitionWriter::visit(AST::LogicalExpression& logicalExpression)
540{
541 checkErrorAndVisit(logicalExpression.left());
542 auto left = m_stack.takeLast();
543 checkErrorAndVisit(logicalExpression.right());
544 auto right = m_stack.takeLast();
545 ASSERT(logicalExpression.resolvedType());
546 auto variableName = generateNextVariableName();
547 m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*logicalExpression.resolvedType()), ' ', variableName, " = ", left));
548 switch (logicalExpression.type()) {
549 case AST::LogicalExpression::Type::And:
550 m_stringBuilder.append(" && ");
551 break;
552 default:
553 ASSERT(logicalExpression.type() == AST::LogicalExpression::Type::Or);
554 m_stringBuilder.append(" || ");
555 break;
556 }
557 m_stringBuilder.append(makeString(right, ";\n"));
558 m_stack.append(variableName);
559}
560
561void FunctionDefinitionWriter::visit(AST::LogicalNotExpression& logicalNotExpression)
562{
563 checkErrorAndVisit(logicalNotExpression.operand());
564 auto operand = m_stack.takeLast();
565 ASSERT(logicalNotExpression.resolvedType());
566 auto variableName = generateNextVariableName();
567 m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*logicalNotExpression.resolvedType()), ' ', variableName, " = !", operand, ";\n"));
568 m_stack.append(variableName);
569}
570
571void FunctionDefinitionWriter::visit(AST::MakeArrayReferenceExpression& makeArrayReferenceExpression)
572{
573 checkErrorAndVisit(makeArrayReferenceExpression.lValue());
574 auto lValue = m_stack.takeLast();
575 ASSERT(makeArrayReferenceExpression.resolvedType());
576 auto variableName = generateNextVariableName();
577 auto mangledTypeName = m_typeNamer.mangledNameForType(*makeArrayReferenceExpression.resolvedType());
578 if (is<AST::PointerType>(*makeArrayReferenceExpression.resolvedType()))
579 m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = { ", lValue, ", 1 };\n"));
580 else if (is<AST::ArrayType>(*makeArrayReferenceExpression.resolvedType())) {
581 auto& arrayType = downcast<AST::ArrayType>(*makeArrayReferenceExpression.resolvedType());
582 m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = { &(", lValue, "[0]), ", arrayType.numElements(), " };\n"));
583 } else
584 m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = { &", lValue, ", 1 };\n"));
585 m_stack.append(variableName);
586}
587
588void FunctionDefinitionWriter::visit(AST::MakePointerExpression& makePointerExpression)
589{
590 checkErrorAndVisit(makePointerExpression.lValue());
591 auto lValue = m_stack.takeLast();
592 ASSERT(makePointerExpression.resolvedType());
593 auto variableName = generateNextVariableName();
594 m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*makePointerExpression.resolvedType()), ' ', variableName, " = &", lValue, ";\n"));
595 m_stack.append(variableName);
596}
597
598void FunctionDefinitionWriter::visit(AST::ReadModifyWriteExpression&)
599{
600 // This should be lowered already.
601 ASSERT_NOT_REACHED();
602}
603
604void FunctionDefinitionWriter::visit(AST::TernaryExpression& ternaryExpression)
605{
606 checkErrorAndVisit(ternaryExpression.predicate());
607 auto check = m_stack.takeLast();
608
609 ASSERT(ternaryExpression.resolvedType());
610 auto variableName = generateNextVariableName();
611 m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*ternaryExpression.resolvedType()), ' ', variableName, ";\n"));
612
613 m_stringBuilder.append(makeString("if (", check, ") {\n"));
614 checkErrorAndVisit(ternaryExpression.bodyExpression());
615 m_stringBuilder.append(makeString(variableName, " = ", m_stack.takeLast(), ";\n"));
616 m_stringBuilder.append("} else {\n");
617 checkErrorAndVisit(ternaryExpression.elseExpression());
618 m_stringBuilder.append(makeString(variableName, " = ", m_stack.takeLast(), ";\n"));
619 m_stringBuilder.append("}\n");
620 m_stack.append(variableName);
621}
622
623void FunctionDefinitionWriter::visit(AST::VariableReference& variableReference)
624{
625 ASSERT(variableReference.variable());
626 auto iterator = m_variableMapping.find(variableReference.variable());
627 ASSERT(iterator != m_variableMapping.end());
628 m_stack.append(iterator->value);
629}
630
631String FunctionDefinitionWriter::constantExpressionString(AST::ConstantExpression& constantExpression)
632{
633 String result;
634 constantExpression.visit(WTF::makeVisitor([&](AST::IntegerLiteral& integerLiteral) {
635 result = makeString("", integerLiteral.value());
636 }, [&](AST::UnsignedIntegerLiteral& unsignedIntegerLiteral) {
637 result = makeString("", unsignedIntegerLiteral.value());
638 }, [&](AST::FloatLiteral& floatLiteral) {
639 result = makeString("", floatLiteral.value());
640 }, [&](AST::NullLiteral&) {
641 result = "nullptr"_str;
642 }, [&](AST::BooleanLiteral& booleanLiteral) {
643 result = booleanLiteral.value() ? "true"_str : "false"_str;
644 }, [&](AST::EnumerationMemberLiteral& enumerationMemberLiteral) {
645 ASSERT(enumerationMemberLiteral.enumerationDefinition());
646 ASSERT(enumerationMemberLiteral.enumerationDefinition());
647 result = makeString(m_typeNamer.mangledNameForType(*enumerationMemberLiteral.enumerationDefinition()), '.', m_typeNamer.mangledNameForEnumerationMember(*enumerationMemberLiteral.enumerationMember()));
648 }));
649 return result;
650}
651
652class RenderFunctionDefinitionWriter : public FunctionDefinitionWriter {
653public:
654 RenderFunctionDefinitionWriter(Intrinsics& intrinsics, TypeNamer& typeNamer, HashMap<AST::FunctionDeclaration*, String>& functionMapping, MatchedRenderSemantics&& matchedSemantics, Layout& layout)
655 : FunctionDefinitionWriter(intrinsics, typeNamer, functionMapping, layout)
656 , m_matchedSemantics(WTFMove(matchedSemantics))
657 {
658 }
659
660private:
661 std::unique_ptr<EntryPointScaffolding> createEntryPointScaffolding(AST::FunctionDefinition&) override;
662
663 MatchedRenderSemantics m_matchedSemantics;
664};
665
666std::unique_ptr<EntryPointScaffolding> RenderFunctionDefinitionWriter::createEntryPointScaffolding(AST::FunctionDefinition& functionDefinition)
667{
668 auto generateNextVariableName = [this]() -> String {
669 return this->generateNextVariableName();
670 };
671 if (&functionDefinition == m_matchedSemantics.vertexShader)
672 return std::make_unique<VertexEntryPointScaffolding>(functionDefinition, m_intrinsics, m_typeNamer, m_matchedSemantics.vertexShaderEntryPointItems, m_matchedSemantics.vertexShaderResourceMap, m_layout, WTFMove(generateNextVariableName), m_matchedSemantics.matchedVertexAttributes);
673 if (&functionDefinition == m_matchedSemantics.fragmentShader)
674 return std::make_unique<FragmentEntryPointScaffolding>(functionDefinition, m_intrinsics, m_typeNamer, m_matchedSemantics.fragmentShaderEntryPointItems, m_matchedSemantics.fragmentShaderResourceMap, m_layout, WTFMove(generateNextVariableName), m_matchedSemantics.matchedColorAttachments);
675 return nullptr;
676}
677
678class ComputeFunctionDefinitionWriter : public FunctionDefinitionWriter {
679public:
680 ComputeFunctionDefinitionWriter(Intrinsics& intrinsics, TypeNamer& typeNamer, HashMap<AST::FunctionDeclaration*, String>& functionMapping, MatchedComputeSemantics&& matchedSemantics, Layout& layout)
681 : FunctionDefinitionWriter(intrinsics, typeNamer, functionMapping, layout)
682 , m_matchedSemantics(WTFMove(matchedSemantics))
683 {
684 }
685
686private:
687 std::unique_ptr<EntryPointScaffolding> createEntryPointScaffolding(AST::FunctionDefinition&) override;
688
689 MatchedComputeSemantics m_matchedSemantics;
690};
691
692std::unique_ptr<EntryPointScaffolding> ComputeFunctionDefinitionWriter::createEntryPointScaffolding(AST::FunctionDefinition& functionDefinition)
693{
694 auto generateNextVariableName = [this]() -> String {
695 return this->generateNextVariableName();
696 };
697 if (&functionDefinition == m_matchedSemantics.shader)
698 return std::make_unique<ComputeEntryPointScaffolding>(functionDefinition, m_intrinsics, m_typeNamer, m_matchedSemantics.entryPointItems, m_matchedSemantics.resourceMap, m_layout, WTFMove(generateNextVariableName));
699 return nullptr;
700}
701
702struct SharedMetalFunctionsResult {
703 HashMap<AST::FunctionDeclaration*, String> functionMapping;
704 String metalFunctions;
705};
706static SharedMetalFunctionsResult sharedMetalFunctions(Program& program, TypeNamer& typeNamer)
707{
708 StringBuilder stringBuilder;
709
710 unsigned numFunctions = 0;
711 HashMap<AST::FunctionDeclaration*, String> functionMapping;
712 for (auto& nativeFunctionDeclaration : program.nativeFunctionDeclarations()) {
713 auto addResult = functionMapping.add(&nativeFunctionDeclaration, makeString("function", numFunctions++));
714 ASSERT_UNUSED(addResult, addResult.isNewEntry);
715 }
716 for (auto& functionDefinition : program.functionDefinitions()) {
717 auto addResult = functionMapping.add(&functionDefinition, makeString("function", numFunctions++));
718 ASSERT_UNUSED(addResult, addResult.isNewEntry);
719 }
720
721 {
722 FunctionDeclarationWriter functionDeclarationWriter(typeNamer, functionMapping);
723 for (auto& nativeFunctionDeclaration : program.nativeFunctionDeclarations())
724 functionDeclarationWriter.visit(nativeFunctionDeclaration);
725 for (auto& functionDefinition : program.functionDefinitions()) {
726 if (!functionDefinition->entryPointType())
727 functionDeclarationWriter.visit(functionDefinition);
728 }
729 stringBuilder.append(functionDeclarationWriter.toString());
730 }
731
732 stringBuilder.append('\n');
733 return { WTFMove(functionMapping), stringBuilder.toString() };
734}
735
736RenderMetalFunctions metalFunctions(Program& program, TypeNamer& typeNamer, MatchedRenderSemantics&& matchedSemantics, Layout& layout)
737{
738 auto sharedMetalFunctions = Metal::sharedMetalFunctions(program, typeNamer);
739
740 StringBuilder stringBuilder;
741 stringBuilder.append(sharedMetalFunctions.metalFunctions);
742
743 auto* vertexShaderEntryPoint = matchedSemantics.vertexShader;
744 auto* fragmentShaderEntryPoint = matchedSemantics.fragmentShader;
745
746 RenderFunctionDefinitionWriter functionDefinitionWriter(program.intrinsics(), typeNamer, sharedMetalFunctions.functionMapping, WTFMove(matchedSemantics), layout);
747 for (auto& nativeFunctionDeclaration : program.nativeFunctionDeclarations())
748 functionDefinitionWriter.visit(nativeFunctionDeclaration);
749 for (auto& functionDefinition : program.functionDefinitions())
750 functionDefinitionWriter.visit(functionDefinition);
751 stringBuilder.append(functionDefinitionWriter.toString());
752
753 RenderMetalFunctions result;
754 result.metalSource = stringBuilder.toString();
755 result.mangledVertexEntryPointName = sharedMetalFunctions.functionMapping.get(vertexShaderEntryPoint);
756 result.mangledFragmentEntryPointName = sharedMetalFunctions.functionMapping.get(fragmentShaderEntryPoint);
757 return result;
758}
759
760ComputeMetalFunctions metalFunctions(Program& program, TypeNamer& typeNamer, MatchedComputeSemantics&& matchedSemantics, Layout& layout)
761{
762 auto sharedMetalFunctions = Metal::sharedMetalFunctions(program, typeNamer);
763
764 StringBuilder stringBuilder;
765 stringBuilder.append(sharedMetalFunctions.metalFunctions);
766
767 auto* entryPoint = matchedSemantics.shader;
768
769 ComputeFunctionDefinitionWriter functionDefinitionWriter(program.intrinsics(), typeNamer, sharedMetalFunctions.functionMapping, WTFMove(matchedSemantics), layout);
770 for (auto& nativeFunctionDeclaration : program.nativeFunctionDeclarations())
771 functionDefinitionWriter.visit(nativeFunctionDeclaration);
772 for (auto& functionDefinition : program.functionDefinitions())
773 functionDefinitionWriter.visit(functionDefinition);
774 stringBuilder.append(functionDefinitionWriter.toString());
775
776 ComputeMetalFunctions result;
777 result.metalSource = stringBuilder.toString();
778 result.mangledEntryPointName = sharedMetalFunctions.functionMapping.get(entryPoint);
779 return result;
780}
781
782} // namespace Metal
783
784} // namespace WHLSL
785
786} // namespace WebCore
787
788#endif
789