| /* |
| * Copyright (C) 2019 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "WHLSLPropertyResolver.h" |
| |
| #if ENABLE(WEBGPU) |
| |
| #include "WHLSLAssignmentExpression.h" |
| #include "WHLSLCallExpression.h" |
| #include "WHLSLCommaExpression.h" |
| #include "WHLSLDereferenceExpression.h" |
| #include "WHLSLDotExpression.h" |
| #include "WHLSLFunctionDeclaration.h" |
| #include "WHLSLFunctionDefinition.h" |
| #include "WHLSLMakeArrayReferenceExpression.h" |
| #include "WHLSLMakePointerExpression.h" |
| #include "WHLSLPointerType.h" |
| #include "WHLSLReadModifyWriteExpression.h" |
| #include "WHLSLReplaceWith.h" |
| #include "WHLSLVariableDeclaration.h" |
| #include "WHLSLVariableReference.h" |
| #include "WHLSLVisitor.h" |
| |
| namespace WebCore { |
| |
| namespace WHLSL { |
| |
| class PropertyResolver : public Visitor { |
| public: |
| private: |
| void visit(AST::FunctionDefinition&) override; |
| void visit(AST::DotExpression&) override; |
| void visit(AST::IndexExpression&) override; |
| void visit(AST::AssignmentExpression&) override; |
| void visit(AST::ReadModifyWriteExpression&) override; |
| |
| void simplifyRightValue(AST::PropertyAccessExpression&); |
| bool simplifyAbstractLeftValue(AST::AssignmentExpression&, AST::DotExpression&, UniqueRef<AST::Expression>&& right); |
| void simplifyLeftValue(AST::Expression&); |
| |
| AST::VariableDeclarations m_variableDeclarations; |
| }; |
| |
| void PropertyResolver::visit(AST::DotExpression& dotExpression) |
| { |
| // Unless we're inside an AssignmentExpression or a ReadModifyWriteExpression, we're a right value. |
| simplifyRightValue(dotExpression); |
| } |
| |
| void PropertyResolver::visit(AST::IndexExpression& indexExpression) |
| { |
| checkErrorAndVisit(indexExpression.indexExpression()); |
| // Unless we're inside an AssignmentExpression or a ReadModifyWriteExpression, we're a right value. |
| simplifyRightValue(indexExpression); |
| } |
| |
| void PropertyResolver::visit(AST::FunctionDefinition& functionDefinition) |
| { |
| Visitor::visit(functionDefinition); |
| if (!m_variableDeclarations.isEmpty()) |
| functionDefinition.block().statements().insert(0, makeUniqueRef<AST::VariableDeclarationsStatement>(functionDefinition.codeLocation(), WTFMove(m_variableDeclarations))); |
| } |
| |
| enum class WhichAnder { |
| ThreadAnder, |
| Ander |
| }; |
| |
| struct AnderCallArgumentResult { |
| UniqueRef<AST::Expression> expression; |
| Optional<UniqueRef<AST::VariableDeclaration>> variableDeclaration; |
| WhichAnder whichAnder; |
| }; |
| |
| template <typename ExpressionConstructor, typename TypeConstructor> |
| static Optional<AnderCallArgumentResult> wrapAnderCallArgument(UniqueRef<AST::Expression>& expression, UniqueRef<AST::UnnamedType> baseType, bool anderFunction, bool threadAnderFunction) |
| { |
| auto location = expression->codeLocation(); |
| if (auto addressSpace = expression->typeAnnotation().leftAddressSpace()) { |
| if (!anderFunction) |
| return WTF::nullopt; |
| auto makeArrayReference = makeUniqueRef<ExpressionConstructor>(location, WTFMove(expression)); |
| makeArrayReference->setType(makeUniqueRef<TypeConstructor>(location, *addressSpace, WTFMove(baseType))); |
| makeArrayReference->setTypeAnnotation(AST::RightValue()); |
| return {{ WTFMove(makeArrayReference), WTF::nullopt, WhichAnder::Ander }}; |
| } |
| if (threadAnderFunction) { |
| auto variableDeclaration = makeUniqueRef<AST::VariableDeclaration>(location, AST::Qualifiers(), baseType->clone(), String(), nullptr, nullptr); |
| |
| auto variableReference1 = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(variableDeclaration)); |
| variableReference1->setType(baseType->clone()); |
| variableReference1->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); |
| |
| auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(location, WTFMove(variableReference1), WTFMove(expression)); |
| assignmentExpression->setType(baseType->clone()); |
| assignmentExpression->setTypeAnnotation(AST::RightValue()); |
| |
| auto variableReference2 = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(variableDeclaration)); |
| variableReference2->setType(baseType->clone()); |
| variableReference2->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); |
| |
| auto expression = makeUniqueRef<ExpressionConstructor>(location, WTFMove(variableReference2)); |
| auto resultType = makeUniqueRef<TypeConstructor>(location, AST::AddressSpace::Thread, WTFMove(baseType)); |
| expression->setType(resultType->clone()); |
| expression->setTypeAnnotation(AST::RightValue()); |
| |
| Vector<UniqueRef<AST::Expression>> expressions; |
| expressions.append(WTFMove(assignmentExpression)); |
| expressions.append(WTFMove(expression)); |
| auto commaExpression = makeUniqueRef<AST::CommaExpression>(location, WTFMove(expressions)); |
| commaExpression->setType(WTFMove(resultType)); |
| commaExpression->setTypeAnnotation(AST::RightValue()); |
| return {{ WTFMove(commaExpression), { WTFMove(variableDeclaration) }, WhichAnder::ThreadAnder}}; |
| } |
| return WTF::nullopt; |
| } |
| |
| static Optional<AnderCallArgumentResult> anderCallArgument(UniqueRef<AST::Expression>& expression, bool anderFunction, bool threadAnderFunction) |
| { |
| if (!anderFunction && !threadAnderFunction) |
| return WTF::nullopt; |
| auto& unifyNode = expression->resolvedType().unifyNode(); |
| if (is<AST::UnnamedType>(unifyNode)) { |
| auto& unnamedType = downcast<AST::UnnamedType>(unifyNode); |
| ASSERT(!is<AST::PointerType>(unnamedType)); |
| if (is<AST::ArrayReferenceType>(unnamedType)) |
| return {{ WTFMove(expression), WTF::nullopt, WhichAnder::Ander }}; |
| if (is<AST::ArrayType>(unnamedType)) |
| return wrapAnderCallArgument<AST::MakeArrayReferenceExpression, AST::ArrayReferenceType>(expression, downcast<AST::ArrayType>(unnamedType).type().clone(), anderFunction, threadAnderFunction); |
| } |
| return wrapAnderCallArgument<AST::MakePointerExpression, AST::PointerType>(expression, expression->resolvedType().clone(), anderFunction, threadAnderFunction); |
| } |
| |
| static Optional<UniqueRef<AST::Expression>> setterCall(AST::PropertyAccessExpression& propertyAccessExpression, AST::FunctionDeclaration* relevantAnder, UniqueRef<AST::Expression>&& newValue, const std::function<UniqueRef<AST::Expression>()>& leftValueFactory, AST::VariableDeclaration* indexVariable) |
| { |
| auto maybeAddIndexArgument = [&](Vector<UniqueRef<AST::Expression>>& arguments) { |
| if (!indexVariable) |
| return; |
| auto variableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(*indexVariable)); |
| ASSERT(indexVariable->type()); |
| variableReference->setType(indexVariable->type()->clone()); |
| variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| arguments.append(WTFMove(variableReference)); |
| }; |
| |
| auto location = propertyAccessExpression.codeLocation(); |
| if (relevantAnder) { |
| // *operator&.foo(&v) = newValue |
| auto leftValue = leftValueFactory(); |
| auto argument = anderCallArgument(leftValue, true, true); |
| ASSERT(argument); |
| ASSERT(!argument->variableDeclaration); |
| ASSERT(argument->whichAnder == WhichAnder::Ander); |
| Vector<UniqueRef<AST::Expression>> arguments; |
| arguments.append(WTFMove(argument->expression)); |
| maybeAddIndexArgument(arguments); |
| |
| auto callExpression = makeUniqueRef<AST::CallExpression>(location, String(relevantAnder->name()), WTFMove(arguments)); |
| callExpression->setType(relevantAnder->type().clone()); |
| callExpression->setTypeAnnotation(AST::RightValue()); |
| callExpression->setFunction(*relevantAnder); |
| |
| auto dereferenceExpression = makeUniqueRef<AST::DereferenceExpression>(location, WTFMove(callExpression)); |
| dereferenceExpression->setType(downcast<AST::PointerType>(relevantAnder->type()).elementType().clone()); |
| dereferenceExpression->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); |
| |
| auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(location, WTFMove(dereferenceExpression), WTFMove(newValue)); |
| assignmentExpression->setType(downcast<AST::PointerType>(relevantAnder->type()).elementType().clone()); |
| assignmentExpression->setTypeAnnotation(AST::RightValue()); |
| |
| return UniqueRef<AST::Expression>(WTFMove(assignmentExpression)); |
| } |
| |
| // v = operator.foo=(v, newValue) |
| ASSERT(propertyAccessExpression.setterFunction()); |
| |
| Vector<UniqueRef<AST::Expression>> arguments; |
| arguments.append(leftValueFactory()); |
| maybeAddIndexArgument(arguments); |
| arguments.append(WTFMove(newValue)); |
| |
| auto callExpression = makeUniqueRef<AST::CallExpression>(location, String(propertyAccessExpression.setterFunction()->name()), WTFMove(arguments)); |
| callExpression->setType(propertyAccessExpression.setterFunction()->type().clone()); |
| callExpression->setTypeAnnotation(AST::RightValue()); |
| callExpression->setFunction(*propertyAccessExpression.setterFunction()); |
| |
| auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(location, leftValueFactory(), WTFMove(callExpression)); |
| assignmentExpression->setType(propertyAccessExpression.setterFunction()->type().clone()); |
| assignmentExpression->setTypeAnnotation(AST::RightValue()); |
| |
| return UniqueRef<AST::Expression>(WTFMove(assignmentExpression)); |
| } |
| |
| static Optional<UniqueRef<AST::Expression>> getterCall(AST::PropertyAccessExpression& propertyAccessExpression, AST::FunctionDeclaration* relevantAnder, const std::function<UniqueRef<AST::Expression>()>& leftValueFactory, AST::VariableDeclaration* indexVariable) |
| { |
| auto maybeAddIndexArgument = [&](Vector<UniqueRef<AST::Expression>>& arguments) { |
| if (!indexVariable) |
| return; |
| auto variableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(*indexVariable)); |
| ASSERT(indexVariable->type()); |
| variableReference->setType(indexVariable->type()->clone()); |
| variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| arguments.append(WTFMove(variableReference)); |
| }; |
| |
| auto location = propertyAccessExpression.codeLocation(); |
| |
| if (relevantAnder) { |
| // *operator&.foo(&v) |
| auto leftValue = leftValueFactory(); |
| auto argument = anderCallArgument(leftValue, true, true); |
| ASSERT(argument); |
| ASSERT(!argument->variableDeclaration); |
| ASSERT(argument->whichAnder == WhichAnder::Ander); |
| Vector<UniqueRef<AST::Expression>> arguments; |
| arguments.append(WTFMove(argument->expression)); |
| maybeAddIndexArgument(arguments); |
| |
| auto callExpression = makeUniqueRef<AST::CallExpression>(location, String(relevantAnder->name()), WTFMove(arguments)); |
| callExpression->setType(relevantAnder->type().clone()); |
| callExpression->setTypeAnnotation(AST::RightValue()); |
| callExpression->setFunction(*relevantAnder); |
| |
| auto dereferenceExpression = makeUniqueRef<AST::DereferenceExpression>(location, WTFMove(callExpression)); |
| dereferenceExpression->setType(downcast<AST::PointerType>(relevantAnder->type()).elementType().clone()); |
| dereferenceExpression->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); |
| |
| return UniqueRef<AST::Expression>(WTFMove(dereferenceExpression)); |
| } |
| |
| // operator.foo(v) |
| ASSERT(propertyAccessExpression.getterFunction()); |
| |
| Vector<UniqueRef<AST::Expression>> arguments; |
| arguments.append(leftValueFactory()); |
| maybeAddIndexArgument(arguments); |
| |
| auto callExpression = makeUniqueRef<AST::CallExpression>(location, String(propertyAccessExpression.getterFunction()->name()), WTFMove(arguments)); |
| callExpression->setType(propertyAccessExpression.getterFunction()->type().clone()); |
| callExpression->setTypeAnnotation(AST::RightValue()); |
| callExpression->setFunction(*propertyAccessExpression.getterFunction()); |
| |
| return UniqueRef<AST::Expression>(WTFMove(callExpression)); |
| } |
| |
| struct ModifyResult { |
| AST::Expression& innerLeftValue; |
| Vector<UniqueRef<AST::Expression>> expressions; |
| Vector<UniqueRef<AST::VariableDeclaration>> variableDeclarations; |
| }; |
| struct ModificationResult { |
| Vector<UniqueRef<AST::Expression>> expressions; |
| UniqueRef<AST::Expression> result; |
| }; |
| static Optional<ModifyResult> modify(AST::PropertyAccessExpression& propertyAccessExpression, std::function<Optional<ModificationResult>(Optional<UniqueRef<AST::Expression>>&&)> modification) |
| { |
| // Consider a.b.c.d++; |
| // This would get transformed into: |
| // |
| // Step 1: |
| // p = &a; |
| // |
| // Step 2: |
| // q = operator.b(*p); |
| // r = operator.c(q); |
| // |
| // Step 3: |
| // oldValue = operator.d(r); |
| // newValue = ...; |
| // |
| // Step 4: |
| // r = operator.d=(r, newValue); |
| // q = operator.c=(q, r); |
| // |
| // Step 5: |
| // *p = operator.b=(*p, q); |
| |
| // If the expression is a.b.c.d = e, Step 3 disappears and "newValue" in step 4 becomes "e". |
| |
| |
| // Find the ".b" ".c" and ".d" expressions. They end up in the order [".d", ".c", ".b"]. |
| Vector<std::reference_wrapper<AST::PropertyAccessExpression>> chain; |
| AST::PropertyAccessExpression* iterator = &propertyAccessExpression; |
| while (true) { |
| chain.append(*iterator); |
| if (iterator->base().typeAnnotation().leftAddressSpace()) |
| break; |
| ASSERT(!iterator->base().typeAnnotation().isRightValue()); |
| iterator = &downcast<AST::PropertyAccessExpression>(iterator->base()); |
| } |
| auto leftExpression = iterator->takeBase(); |
| AST::Expression& innerLeftExpression = leftExpression; |
| |
| // Create "p" variable. |
| auto pointerVariable = makeUniqueRef<AST::VariableDeclaration>(leftExpression->codeLocation(), AST::Qualifiers(), UniqueRef<AST::UnnamedType>(makeUniqueRef<AST::PointerType>(leftExpression->codeLocation(), *leftExpression->typeAnnotation().leftAddressSpace(), leftExpression->resolvedType().clone())), String(), nullptr, nullptr); |
| |
| // Create "q" and "r" variables. |
| Vector<UniqueRef<AST::VariableDeclaration>> intermediateVariables; |
| intermediateVariables.reserveInitialCapacity(chain.size() - 1); |
| for (size_t i = 1; i < chain.size(); ++i) { |
| auto& propertyAccessExpression = static_cast<AST::PropertyAccessExpression&>(chain[i]); |
| intermediateVariables.uncheckedAppend(makeUniqueRef<AST::VariableDeclaration>(propertyAccessExpression.codeLocation(), AST::Qualifiers(), propertyAccessExpression.resolvedType().clone(), String(), nullptr, nullptr)); |
| } |
| |
| // Consider a[foo()][b] = c; |
| // Naively, This would get expanded to: |
| // |
| // temp = operator[](a, foo()); |
| // temp = operator[]=(temp, b, c); |
| // a = operator[]=(a, foo(), temp); |
| // |
| // However, if we did this, we would have to run foo() twice, which would be incorrect. |
| // Instead, we need to save foo() and b into more temporary variables. |
| // These temporary variables are parallel to "chain" above, with nullopt referring to a DotExpression (which doesn't have an index value to save to a variable). |
| // |
| // Instead, this gets expanded to: |
| // |
| // p = &a; |
| // temp = foo(); |
| // q = operator[](*p, temp); |
| // temp2 = b; |
| // q = operator[]=(q, temp2, c); |
| // *p = operator[]=(*p, temp, q); |
| |
| Vector<Optional<UniqueRef<AST::VariableDeclaration>>> indexVariables; |
| indexVariables.reserveInitialCapacity(chain.size()); |
| for (AST::PropertyAccessExpression& propertyAccessExpression : chain) { |
| if (!is<AST::IndexExpression>(propertyAccessExpression)) { |
| indexVariables.append(WTF::nullopt); |
| continue; |
| } |
| auto& indexExpression = downcast<AST::IndexExpression>(propertyAccessExpression); |
| indexVariables.uncheckedAppend(makeUniqueRef<AST::VariableDeclaration>(propertyAccessExpression.codeLocation(), AST::Qualifiers(), indexExpression.indexExpression().resolvedType().clone(), String(), nullptr, nullptr)); |
| } |
| |
| Vector<UniqueRef<AST::Expression>> expressions; |
| |
| // Step 1: |
| { |
| auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(innerLeftExpression.codeLocation(), WTFMove(leftExpression)); |
| makePointerExpression->setType(makeUniqueRef<AST::PointerType>(innerLeftExpression.codeLocation(), *innerLeftExpression.typeAnnotation().leftAddressSpace(), innerLeftExpression.resolvedType().clone())); |
| makePointerExpression->setTypeAnnotation(AST::RightValue()); |
| |
| auto variableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(pointerVariable)); |
| ASSERT(pointerVariable->type()); |
| variableReference->setType(pointerVariable->type()->clone()); |
| variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| |
| auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(innerLeftExpression.codeLocation(), WTFMove(variableReference), WTFMove(makePointerExpression)); |
| assignmentExpression->setType(pointerVariable->type()->clone()); |
| assignmentExpression->setTypeAnnotation(AST::RightValue()); |
| |
| expressions.append(WTFMove(assignmentExpression)); |
| } |
| |
| // Step 2: |
| AST::VariableDeclaration* previous = nullptr; |
| auto previousLeftValue = [&]() -> UniqueRef<AST::Expression> { |
| if (previous) { |
| auto variableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(*previous)); |
| ASSERT(previous->type()); |
| variableReference->setType(previous->type()->clone()); |
| variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| return variableReference; |
| } |
| |
| auto variableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(pointerVariable)); |
| ASSERT(pointerVariable->type()); |
| variableReference->setType(pointerVariable->type()->clone()); |
| variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| |
| auto dereferenceExpression = makeUniqueRef<AST::DereferenceExpression>(propertyAccessExpression.codeLocation(), WTFMove(variableReference)); |
| ASSERT(pointerVariable->type()); |
| dereferenceExpression->setType(downcast<AST::PointerType>(*pointerVariable->type()).elementType().clone()); |
| dereferenceExpression->setTypeAnnotation(AST::LeftValue { downcast<AST::PointerType>(*pointerVariable->type()).addressSpace() }); |
| return dereferenceExpression; |
| }; |
| auto appendIndexAssignment = [&](AST::PropertyAccessExpression& propertyAccessExpression, Optional<UniqueRef<AST::VariableDeclaration>>& indexVariable) { |
| if (!indexVariable) |
| return; |
| |
| auto& indexExpression = downcast<AST::IndexExpression>(propertyAccessExpression); |
| |
| auto variableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(*indexVariable)); |
| ASSERT(indexVariable->get().type()); |
| variableReference->setType(indexVariable->get().type()->clone()); |
| variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| |
| auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(propertyAccessExpression.codeLocation(), WTFMove(variableReference), indexExpression.takeIndex()); |
| assignmentExpression->setType(indexVariable->get().type()->clone()); |
| assignmentExpression->setTypeAnnotation(AST::RightValue()); |
| |
| expressions.append(WTFMove(assignmentExpression)); |
| }; |
| for (size_t i = chain.size(); --i; ) { |
| AST::PropertyAccessExpression& propertyAccessExpression = chain[i]; |
| AST::VariableDeclaration& variableDeclaration = intermediateVariables[i - 1]; |
| Optional<UniqueRef<AST::VariableDeclaration>>& indexVariable = indexVariables[i]; |
| |
| appendIndexAssignment(propertyAccessExpression, indexVariable); |
| |
| AST::FunctionDeclaration* relevantAnder = i == chain.size() - 1 ? propertyAccessExpression.anderFunction() : propertyAccessExpression.threadAnderFunction(); |
| auto callExpression = getterCall(propertyAccessExpression, relevantAnder, previousLeftValue, indexVariable ? &*indexVariable : nullptr); |
| |
| if (!callExpression) |
| return WTF::nullopt; |
| |
| auto variableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(variableDeclaration)); |
| ASSERT(variableDeclaration.type()); |
| variableReference->setType(variableDeclaration.type()->clone()); |
| variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| |
| auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(propertyAccessExpression.codeLocation(), WTFMove(variableReference), WTFMove(*callExpression)); |
| assignmentExpression->setType(variableDeclaration.type()->clone()); |
| assignmentExpression->setTypeAnnotation(AST::RightValue()); |
| |
| expressions.append(WTFMove(assignmentExpression)); |
| |
| previous = &variableDeclaration; |
| } |
| appendIndexAssignment(chain[0], indexVariables[0]); |
| AST::FunctionDeclaration* relevantAnder = chain.size() == 1 ? propertyAccessExpression.anderFunction() : propertyAccessExpression.threadAnderFunction(); |
| auto lastGetterCallExpression = getterCall(chain[0], relevantAnder, previousLeftValue, indexVariables[0] ? &*(indexVariables[0]) : nullptr); |
| |
| // Step 3: |
| auto modificationResult = modification(WTFMove(lastGetterCallExpression)); |
| if (!modificationResult) |
| return WTF::nullopt; |
| for (size_t i = 0; i < modificationResult->expressions.size(); ++i) |
| expressions.append(WTFMove(modificationResult->expressions[i])); |
| |
| // Step 4: |
| UniqueRef<AST::Expression> rightValue = WTFMove(modificationResult->result); |
| auto expressionType = rightValue->resolvedType().clone(); |
| for (size_t i = 0; i < chain.size() - 1; ++i) { |
| AST::PropertyAccessExpression& propertyAccessExpression = chain[i]; |
| AST::VariableDeclaration& variableDeclaration = intermediateVariables[i]; |
| Optional<UniqueRef<AST::VariableDeclaration>>& indexVariable = indexVariables[i]; |
| |
| auto assignmentExpression = setterCall(propertyAccessExpression, propertyAccessExpression.threadAnderFunction(), WTFMove(rightValue), [&]() -> UniqueRef<AST::Expression> { |
| auto variableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(variableDeclaration)); |
| ASSERT(variableDeclaration.type()); |
| variableReference->setType(variableDeclaration.type()->clone()); |
| variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| return variableReference; |
| }, indexVariable ? &*indexVariable : nullptr); |
| |
| if (!assignmentExpression) |
| return WTF::nullopt; |
| |
| expressions.append(WTFMove(*assignmentExpression)); |
| |
| rightValue = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(variableDeclaration)); |
| ASSERT(variableDeclaration.type()); |
| rightValue->setType(variableDeclaration.type()->clone()); |
| rightValue->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| } |
| |
| // Step 5: |
| { |
| AST::PropertyAccessExpression& propertyAccessExpression = chain[chain.size() - 1]; |
| auto assignmentExpression = setterCall(propertyAccessExpression, propertyAccessExpression.anderFunction(), WTFMove(rightValue), [&]() -> UniqueRef<AST::Expression> { |
| auto variableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(pointerVariable)); |
| ASSERT(pointerVariable->type()); |
| variableReference->setType(pointerVariable->type()->clone()); |
| variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| |
| auto dereferenceExpression = makeUniqueRef<AST::DereferenceExpression>(propertyAccessExpression.codeLocation(), WTFMove(variableReference)); |
| ASSERT(pointerVariable->type()); |
| dereferenceExpression->setType(downcast<AST::PointerType>(*pointerVariable->type()).elementType().clone()); |
| dereferenceExpression->setTypeAnnotation(AST::LeftValue { downcast<AST::PointerType>(*pointerVariable->type()).addressSpace() }); |
| return dereferenceExpression; |
| }, indexVariables[indexVariables.size() - 1] ? &*(indexVariables[indexVariables.size() - 1]) : nullptr); |
| |
| if (!assignmentExpression) |
| return WTF::nullopt; |
| |
| expressions.append(WTFMove(*assignmentExpression)); |
| } |
| |
| Vector<UniqueRef<AST::VariableDeclaration>> variableDeclarations; |
| variableDeclarations.append(WTFMove(pointerVariable)); |
| for (auto& intermediateVariable : intermediateVariables) |
| variableDeclarations.append(WTFMove(intermediateVariable)); |
| for (auto& indexVariable : indexVariables) { |
| if (indexVariable) |
| variableDeclarations.append(WTFMove(*indexVariable)); |
| } |
| |
| return {{ innerLeftExpression, WTFMove(expressions), WTFMove(variableDeclarations) }}; |
| } |
| |
| void PropertyResolver::visit(AST::AssignmentExpression& assignmentExpression) |
| { |
| if (assignmentExpression.left().typeAnnotation().leftAddressSpace()) { |
| simplifyLeftValue(assignmentExpression.left()); |
| checkErrorAndVisit(assignmentExpression.right()); |
| return; |
| } |
| ASSERT(!assignmentExpression.left().typeAnnotation().isRightValue()); |
| |
| auto type = assignmentExpression.right().resolvedType().clone(); |
| |
| checkErrorAndVisit(assignmentExpression.right()); |
| |
| auto modifyResult = modify(downcast<AST::PropertyAccessExpression>(assignmentExpression.left()), [&](Optional<UniqueRef<AST::Expression>>&&) -> Optional<ModificationResult> { |
| return {{ Vector<UniqueRef<AST::Expression>>(), assignmentExpression.takeRight() }}; |
| }); |
| |
| if (!modifyResult) { |
| setError(); |
| return; |
| } |
| simplifyLeftValue(modifyResult->innerLeftValue); |
| |
| auto location = assignmentExpression.codeLocation(); |
| auto* commaExpression = AST::replaceWith<AST::CommaExpression>(assignmentExpression, location, WTFMove(modifyResult->expressions)); |
| commaExpression->setType(WTFMove(type)); |
| commaExpression->setTypeAnnotation(AST::RightValue()); |
| |
| for (auto& variableDeclaration : modifyResult->variableDeclarations) |
| m_variableDeclarations.append(WTFMove(variableDeclaration)); |
| } |
| |
| void PropertyResolver::visit(AST::ReadModifyWriteExpression& readModifyWriteExpression) |
| { |
| checkErrorAndVisit(readModifyWriteExpression.newValueExpression()); |
| if (error()) |
| return; |
| |
| auto location = readModifyWriteExpression.codeLocation(); |
| auto leftValueLocation = readModifyWriteExpression.leftValue().codeLocation(); |
| |
| if (readModifyWriteExpression.leftValue().typeAnnotation().leftAddressSpace()) { |
| // Consider a++; |
| // This would get transformed into: |
| // |
| // p = &a; |
| // oldValue = *p; |
| // newValue = ...; |
| // *p = newValue; |
| |
| simplifyLeftValue(readModifyWriteExpression.leftValue()); |
| |
| auto baseType = readModifyWriteExpression.leftValue().resolvedType().clone(); |
| auto pointerType = makeUniqueRef<AST::PointerType>(leftValueLocation, *readModifyWriteExpression.leftValue().typeAnnotation().leftAddressSpace(), baseType->clone()); |
| |
| auto pointerVariable = makeUniqueRef<AST::VariableDeclaration>(leftValueLocation, AST::Qualifiers(), UniqueRef<AST::UnnamedType>(pointerType->clone()), String(), nullptr, nullptr); |
| |
| Vector<UniqueRef<AST::Expression>> expressions; |
| |
| { |
| auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(leftValueLocation, readModifyWriteExpression.takeLeftValue()); |
| makePointerExpression->setType(pointerType->clone()); |
| makePointerExpression->setTypeAnnotation(AST::RightValue()); |
| |
| auto variableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(pointerVariable)); |
| variableReference->setType(pointerType->clone()); |
| variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| |
| auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(leftValueLocation, WTFMove(variableReference), WTFMove(makePointerExpression)); |
| assignmentExpression->setType(pointerType->clone()); |
| assignmentExpression->setTypeAnnotation(AST::RightValue()); |
| |
| expressions.append(WTFMove(assignmentExpression)); |
| } |
| |
| { |
| auto variableReference1 = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(pointerVariable)); |
| variableReference1->setType(pointerType->clone()); |
| variableReference1->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| |
| auto dereferenceExpression = makeUniqueRef<AST::DereferenceExpression>(location, WTFMove(variableReference1)); |
| dereferenceExpression->setType(baseType->clone()); |
| dereferenceExpression->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| |
| auto variableReference2 = readModifyWriteExpression.oldVariableReference(); |
| variableReference2->setType(baseType->clone()); |
| variableReference2->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| |
| auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(location, WTFMove(variableReference2), WTFMove(dereferenceExpression)); |
| assignmentExpression->setType(baseType->clone()); |
| assignmentExpression->setTypeAnnotation(AST::RightValue()); |
| |
| expressions.append(WTFMove(assignmentExpression)); |
| } |
| |
| { |
| auto variableReference = readModifyWriteExpression.newVariableReference(); |
| variableReference->setType(baseType->clone()); |
| variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| |
| auto newValueExpression = readModifyWriteExpression.takeNewValueExpression(); |
| auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(location, WTFMove(variableReference), WTFMove(newValueExpression)); |
| assignmentExpression->setType(baseType->clone()); |
| assignmentExpression->setTypeAnnotation(AST::RightValue()); |
| |
| expressions.append(WTFMove(assignmentExpression)); |
| } |
| |
| { |
| auto variableReference1 = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(pointerVariable)); |
| variableReference1->setType(pointerType->clone()); |
| variableReference1->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| |
| auto dereferenceExpression = makeUniqueRef<AST::DereferenceExpression>(location, WTFMove(variableReference1)); |
| dereferenceExpression->setType(baseType->clone()); |
| dereferenceExpression->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| |
| auto variableReference2 = readModifyWriteExpression.newVariableReference(); |
| variableReference2->setType(baseType->clone()); |
| variableReference2->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| |
| auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(location, WTFMove(dereferenceExpression), WTFMove(variableReference2)); |
| assignmentExpression->setType(baseType->clone()); |
| assignmentExpression->setTypeAnnotation(AST::RightValue()); |
| |
| expressions.append(WTFMove(assignmentExpression)); |
| } |
| |
| auto resultExpression = readModifyWriteExpression.takeResultExpression(); |
| auto type = resultExpression->resolvedType().clone(); |
| expressions.append(WTFMove(resultExpression)); |
| |
| UniqueRef<AST::VariableDeclaration> oldVariableDeclaration = readModifyWriteExpression.takeOldValue(); |
| UniqueRef<AST::VariableDeclaration> newVariableDeclaration = readModifyWriteExpression.takeNewValue(); |
| |
| auto* commaExpression = AST::replaceWith<AST::CommaExpression>(readModifyWriteExpression, location, WTFMove(expressions)); |
| commaExpression->setType(WTFMove(type)); |
| commaExpression->setTypeAnnotation(AST::RightValue()); |
| |
| m_variableDeclarations.append(WTFMove(pointerVariable)); |
| m_variableDeclarations.append(WTFMove(oldVariableDeclaration)); |
| m_variableDeclarations.append(WTFMove(newVariableDeclaration)); |
| return; |
| } |
| |
| ASSERT(!readModifyWriteExpression.leftValue().typeAnnotation().isRightValue()); |
| if (!is<AST::PropertyAccessExpression>(readModifyWriteExpression.leftValue())) { |
| setError(); |
| return; |
| } |
| auto modifyResult = modify(downcast<AST::PropertyAccessExpression>(readModifyWriteExpression.leftValue()), [&](Optional<UniqueRef<AST::Expression>>&& lastGetterCallExpression) -> Optional<ModificationResult> { |
| Vector<UniqueRef<AST::Expression>> expressions; |
| if (!lastGetterCallExpression) |
| return WTF::nullopt; |
| |
| { |
| auto variableReference = readModifyWriteExpression.oldVariableReference(); |
| variableReference->setType(readModifyWriteExpression.leftValue().resolvedType().clone()); |
| variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| |
| auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(leftValueLocation, WTFMove(variableReference), WTFMove(*lastGetterCallExpression)); |
| assignmentExpression->setType(readModifyWriteExpression.leftValue().resolvedType().clone()); |
| assignmentExpression->setTypeAnnotation(AST::RightValue()); |
| |
| expressions.append(WTFMove(assignmentExpression)); |
| } |
| |
| { |
| auto variableReference = readModifyWriteExpression.newVariableReference(); |
| variableReference->setType(readModifyWriteExpression.leftValue().resolvedType().clone()); |
| variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| |
| auto newValueExpression = readModifyWriteExpression.takeNewValueExpression(); |
| auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(leftValueLocation, WTFMove(variableReference), WTFMove(newValueExpression)); |
| assignmentExpression->setType(readModifyWriteExpression.leftValue().resolvedType().clone()); |
| assignmentExpression->setTypeAnnotation(AST::RightValue()); |
| |
| expressions.append(WTFMove(assignmentExpression)); |
| } |
| |
| auto variableReference = readModifyWriteExpression.newVariableReference(); |
| variableReference->setType(readModifyWriteExpression.leftValue().resolvedType().clone()); |
| variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? |
| |
| return {{ WTFMove(expressions), WTFMove(variableReference) }}; |
| }); |
| |
| if (!modifyResult) { |
| setError(); |
| return; |
| } |
| simplifyLeftValue(modifyResult->innerLeftValue); |
| |
| auto resultExpression = readModifyWriteExpression.takeResultExpression(); |
| auto type = resultExpression->resolvedType().clone(); |
| modifyResult->expressions.append(WTFMove(resultExpression)); |
| |
| UniqueRef<AST::VariableDeclaration> oldVariableDeclaration = readModifyWriteExpression.takeOldValue(); |
| UniqueRef<AST::VariableDeclaration> newVariableDeclaration = readModifyWriteExpression.takeNewValue(); |
| |
| auto* commaExpression = AST::replaceWith<AST::CommaExpression>(readModifyWriteExpression, location, WTFMove(modifyResult->expressions)); |
| commaExpression->setType(WTFMove(type)); |
| commaExpression->setTypeAnnotation(AST::RightValue()); |
| |
| for (auto& variableDeclaration : modifyResult->variableDeclarations) |
| m_variableDeclarations.append(WTFMove(variableDeclaration)); |
| m_variableDeclarations.append(WTFMove(oldVariableDeclaration)); |
| m_variableDeclarations.append(WTFMove(newVariableDeclaration)); |
| } |
| |
| static Optional<AnderCallArgumentResult> anderCallArgument(AST::PropertyAccessExpression& propertyAccessExpression) |
| { |
| return anderCallArgument(propertyAccessExpression.baseReference(), propertyAccessExpression.anderFunction(), propertyAccessExpression.threadAnderFunction()); |
| } |
| |
| void PropertyResolver::simplifyRightValue(AST::PropertyAccessExpression& propertyAccessExpression) |
| { |
| auto location = propertyAccessExpression.codeLocation(); |
| |
| checkErrorAndVisit(propertyAccessExpression.base()); |
| |
| if (auto argument = anderCallArgument(propertyAccessExpression)) { |
| auto* anderFunction = argument->whichAnder == WhichAnder::ThreadAnder ? propertyAccessExpression.threadAnderFunction() : propertyAccessExpression.anderFunction(); |
| ASSERT(anderFunction); |
| Vector<UniqueRef<AST::Expression>> arguments; |
| arguments.append(WTFMove(argument->expression)); |
| if (is<AST::IndexExpression>(propertyAccessExpression)) |
| arguments.append(downcast<AST::IndexExpression>(propertyAccessExpression).takeIndex()); |
| auto callExpression = makeUniqueRef<AST::CallExpression>(location, String(anderFunction->name()), WTFMove(arguments)); |
| callExpression->setType(anderFunction->type().clone()); |
| callExpression->setTypeAnnotation(AST::RightValue()); |
| callExpression->setFunction(*anderFunction); |
| |
| auto* dereferenceExpression = AST::replaceWith<AST::DereferenceExpression>(propertyAccessExpression, location, WTFMove(callExpression)); |
| dereferenceExpression->setType(downcast<AST::PointerType>(anderFunction->type()).elementType().clone()); |
| dereferenceExpression->setTypeAnnotation(AST::LeftValue { downcast<AST::PointerType>(anderFunction->type()).addressSpace() }); |
| |
| if (auto& variableDeclaration = argument->variableDeclaration) |
| m_variableDeclarations.append(WTFMove(*variableDeclaration)); |
| |
| return; |
| } |
| |
| ASSERT(propertyAccessExpression.getterFunction()); |
| auto& getterFunction = *propertyAccessExpression.getterFunction(); |
| Vector<UniqueRef<AST::Expression>> arguments; |
| arguments.append(propertyAccessExpression.takeBase()); |
| AST::CallExpression* callExpression; |
| if (is<AST::IndexExpression>(propertyAccessExpression)) { |
| auto& indexExpression = downcast<AST::IndexExpression>(propertyAccessExpression); |
| arguments.append(indexExpression.takeIndex()); |
| callExpression = AST::replaceWith<AST::CallExpression>(indexExpression, location, String(getterFunction.name()), WTFMove(arguments)); |
| } else { |
| ASSERT(is<AST::DotExpression>(propertyAccessExpression)); |
| auto& dotExpression = downcast<AST::DotExpression>(propertyAccessExpression); |
| callExpression = AST::replaceWith<AST::CallExpression>(dotExpression, location, String(getterFunction.name()), WTFMove(arguments)); |
| } |
| callExpression->setFunction(getterFunction); |
| callExpression->setType(getterFunction.type().clone()); |
| callExpression->setTypeAnnotation(AST::RightValue()); |
| } |
| |
| class LeftValueSimplifier : public Visitor { |
| private: |
| void visit(AST::DotExpression&) override; |
| void visit(AST::IndexExpression&) override; |
| void visit(AST::DereferenceExpression&) override; |
| |
| void finishVisiting(AST::PropertyAccessExpression&); |
| }; |
| |
| void LeftValueSimplifier::finishVisiting(AST::PropertyAccessExpression& propertyAccessExpression) |
| { |
| ASSERT(propertyAccessExpression.base().typeAnnotation().leftAddressSpace()); |
| ASSERT(propertyAccessExpression.anderFunction()); |
| |
| Visitor::visit(propertyAccessExpression.base()); |
| |
| auto location = propertyAccessExpression.codeLocation(); |
| auto* anderFunction = propertyAccessExpression.anderFunction(); |
| |
| auto argument = anderCallArgument(propertyAccessExpression); |
| ASSERT(argument); |
| ASSERT(!argument->variableDeclaration); |
| ASSERT(argument->whichAnder == WhichAnder::Ander); |
| |
| Vector<UniqueRef<AST::Expression>> arguments; |
| arguments.append(WTFMove(argument->expression)); |
| if (is<AST::IndexExpression>(propertyAccessExpression)) |
| arguments.append(downcast<AST::IndexExpression>(propertyAccessExpression).takeIndex()); |
| auto callExpression = makeUniqueRef<AST::CallExpression>(location, String(anderFunction->name()), WTFMove(arguments)); |
| callExpression->setType(anderFunction->type().clone()); |
| callExpression->setTypeAnnotation(AST::RightValue()); |
| callExpression->setFunction(*anderFunction); |
| |
| auto* dereferenceExpression = AST::replaceWith<AST::DereferenceExpression>(propertyAccessExpression, location, WTFMove(callExpression)); |
| dereferenceExpression->setType(downcast<AST::PointerType>(anderFunction->type()).elementType().clone()); |
| dereferenceExpression->setTypeAnnotation(AST::LeftValue { downcast<AST::PointerType>(anderFunction->type()).addressSpace() }); |
| } |
| |
| void LeftValueSimplifier::visit(AST::DotExpression& dotExpression) |
| { |
| Visitor::visit(dotExpression); |
| finishVisiting(dotExpression); |
| } |
| |
| void LeftValueSimplifier::visit(AST::IndexExpression& indexExpression) |
| { |
| PropertyResolver().Visitor::visit(indexExpression.indexExpression()); |
| finishVisiting(indexExpression); |
| } |
| |
| void LeftValueSimplifier::visit(AST::DereferenceExpression& dereferenceExpression) |
| { |
| // Dereference expressions are the only expressions where the children might be more-right than we are. |
| // For example, a dereference expression may be a left value but its child may be a call expression which is a right value. |
| // LeftValueSimplifier doesn't handle right values, so we instead need to use PropertyResolver. |
| PropertyResolver().Visitor::visit(dereferenceExpression); |
| } |
| |
| void PropertyResolver::simplifyLeftValue(AST::Expression& expression) |
| { |
| LeftValueSimplifier().Visitor::visit(expression); |
| } |
| |
| void resolveProperties(Program& program) |
| { |
| PropertyResolver().Visitor::visit(program); |
| } |
| |
| } // namespace WHLSL |
| |
| } // namespace WebCore |
| |
| #endif // ENABLE(WEBGPU) |