| 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 | |