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 | |
73 | namespace WebCore { |
74 | |
75 | namespace WHLSL { |
76 | |
77 | namespace Metal { |
78 | |
79 | class FunctionDeclarationWriter : public Visitor { |
80 | public: |
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 | |
93 | private: |
94 | TypeNamer& m_typeNamer; |
95 | HashMap<AST::FunctionDeclaration*, String>& m_functionMapping; |
96 | StringBuilder m_stringBuilder; |
97 | }; |
98 | |
99 | void 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 | |
115 | class FunctionDefinitionWriter : public Visitor { |
116 | public: |
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 | |
132 | protected: |
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 | |
192 | void 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 | |
199 | void 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(¶meter, 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 | |
239 | void FunctionDefinitionWriter::visit(AST::FunctionDeclaration&) |
240 | { |
241 | ASSERT_NOT_REACHED(); |
242 | } |
243 | |
244 | void FunctionDefinitionWriter::visit(AST::Statement& statement) |
245 | { |
246 | Visitor::visit(statement); |
247 | } |
248 | |
249 | void 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 | |
257 | void FunctionDefinitionWriter::visit(AST::Break&) |
258 | { |
259 | m_stringBuilder.append("break;\n" ); |
260 | } |
261 | |
262 | void 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 | |
268 | void 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 | |
277 | void 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 | |
283 | void 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 | |
288 | void 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 | |
310 | void 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 | |
322 | void 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 | |
336 | void 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 | |
346 | void 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 | |
357 | void FunctionDefinitionWriter::visit(AST::Trap&) |
358 | { |
359 | // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195811 Implement this |
360 | notImplemented(); |
361 | } |
362 | |
363 | void FunctionDefinitionWriter::visit(AST::VariableDeclarationsStatement& variableDeclarationsStatement) |
364 | { |
365 | Visitor::visit(variableDeclarationsStatement); |
366 | } |
367 | |
368 | void 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 | |
377 | void 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 | |
386 | void 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 | |
395 | void 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 | |
404 | void 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 | |
422 | void 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 | |
431 | void 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 | |
442 | void FunctionDefinitionWriter::visit(AST::Expression& expression) |
443 | { |
444 | Visitor::visit(expression); |
445 | } |
446 | |
447 | void 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 | |
455 | void 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 | |
463 | void 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 | |
471 | void 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 | |
487 | void 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 | |
497 | void 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 | |
519 | void 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 | |
529 | void 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 | |
539 | void 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 | |
561 | void 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 | |
571 | void 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 | |
588 | void 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 | |
598 | void FunctionDefinitionWriter::visit(AST::ReadModifyWriteExpression&) |
599 | { |
600 | // This should be lowered already. |
601 | ASSERT_NOT_REACHED(); |
602 | } |
603 | |
604 | void 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 | |
623 | void 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 | |
631 | String 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 | |
652 | class RenderFunctionDefinitionWriter : public FunctionDefinitionWriter { |
653 | public: |
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 | |
660 | private: |
661 | std::unique_ptr<EntryPointScaffolding> createEntryPointScaffolding(AST::FunctionDefinition&) override; |
662 | |
663 | MatchedRenderSemantics m_matchedSemantics; |
664 | }; |
665 | |
666 | std::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 | |
678 | class ComputeFunctionDefinitionWriter : public FunctionDefinitionWriter { |
679 | public: |
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 | |
686 | private: |
687 | std::unique_ptr<EntryPointScaffolding> createEntryPointScaffolding(AST::FunctionDefinition&) override; |
688 | |
689 | MatchedComputeSemantics m_matchedSemantics; |
690 | }; |
691 | |
692 | std::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 | |
702 | struct SharedMetalFunctionsResult { |
703 | HashMap<AST::FunctionDeclaration*, String> functionMapping; |
704 | String metalFunctions; |
705 | }; |
706 | static 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 | |
736 | RenderMetalFunctions 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 | |
760 | ComputeMetalFunctions 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 | |