WebKit Bugzilla
Attachment 371101 Details for
Bug 198399
: [WHLSL] Educate the property resolver about IndexExpressions
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
WIP
bug-198399-20190531185326.patch (text/plain), 104.88 KB, created by
Myles C. Maxfield
on 2019-05-31 18:53:27 PDT
(
hide
)
Description:
WIP
Filename:
MIME Type:
Creator:
Myles C. Maxfield
Created:
2019-05-31 18:53:27 PDT
Size:
104.88 KB
patch
obsolete
>Subversion Revision: 245984 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index f7c24b59508af36cf0385615d71ba149d9bd4e03..5ae095a10d3c670ca83dcee25a9ccff32b49a403 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,28 @@ >+2019-05-31 Myles C. Maxfield <mmaxfield@apple.com> >+ >+ [WHLSL] Educate the property resolver about IndexExpressions >+ https://bugs.webkit.org/show_bug.cgi?id=198399 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ No new tests (OOPS!). >+ >+ * Modules/webgpu/WHLSL/AST/WHLSLIndexExpression.h: >+ (WebCore::WHLSL::AST::IndexExpression::takeIndex): >+ * Modules/webgpu/WHLSL/AST/WHLSLReferenceType.h: >+ * Modules/webgpu/WHLSL/WHLSLChecker.cpp: >+ (WebCore::WHLSL::Checker::finishVisiting): >+ (WebCore::WHLSL::Checker::visit): >+ * Modules/webgpu/WHLSL/WHLSLInferTypes.h: >+ * Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp: >+ (WebCore::WHLSL::PropertyResolver::visit): >+ (WebCore::WHLSL::setterCall): >+ (WebCore::WHLSL::getterCall): >+ (WebCore::WHLSL::modify): >+ (WebCore::WHLSL::PropertyResolver::simplifyRightValue): >+ (WebCore::WHLSL::LeftValueSimplifier::finishVisiting): >+ (WebCore::WHLSL::LeftValueSimplifier::visit): >+ > 2019-05-31 Andres Gonzalez <andresg_22@apple.com> > > Inserting a newline in contenteditable causes two characters to be added instead of one >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLAddressSpace.h b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLAddressSpace.h >index 425d134667851dab85c827b250cb57afdefc2dde..aba33d5d07834176360a8b3bf8173dbae300281f 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLAddressSpace.h >+++ b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLAddressSpace.h >@@ -43,7 +43,7 @@ enum class AddressSpace : uint8_t { > Thread > }; > >-static ALWAYS_INLINE String toString(AddressSpace addressSpace) >+ALWAYS_INLINE String toString(AddressSpace addressSpace) > { > switch (addressSpace) { > case AddressSpace::Constant: >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLEntryPointType.h b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLEntryPointType.h >index 65f6873b46909dead4cb20262b7536e117e57d22..b45424fd3fd387ed0a3ffb1d103a765560088dbc 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLEntryPointType.h >+++ b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLEntryPointType.h >@@ -41,7 +41,7 @@ enum class EntryPointType : uint8_t { > Compute, > }; > >-static ALWAYS_INLINE String toString(EntryPointType type) >+ALWAYS_INLINE String toString(EntryPointType type) > { > switch (type) { > case EntryPointType::Vertex: >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLIndexExpression.h b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLIndexExpression.h >index aa197b5af43bd60388c7185ad146e8ec03d32e8c..5e49116ab84f67fc026e4572cbe8f5844c813364 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLIndexExpression.h >+++ b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLIndexExpression.h >@@ -59,15 +59,16 @@ public: > > String setterFunctionName() const override > { >- return "operator&[]"_str; >+ return "operator[]="_str; > } > > String anderFunctionName() const override > { >- return "operator[]="_str; >+ return "operator&[]"_str; > } > > Expression& indexExpression() { return m_index; } >+ UniqueRef<Expression> takeIndex() { return WTFMove(m_index); } > > private: > UniqueRef<Expression> m_index; >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLReferenceType.h b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLReferenceType.h >index 8811ac9ad427dd02e7f141b06432bc5033869653..1e6ce164c6cbdb1938c92b594e0060e091295944 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLReferenceType.h >+++ b/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLReferenceType.h >@@ -53,7 +53,7 @@ public: > ReferenceType(const ReferenceType&) = delete; > ReferenceType(ReferenceType&&) = default; > >- bool isReferenceType() const override { return false; } >+ bool isReferenceType() const override { return true; } > > AddressSpace addressSpace() const { return m_addressSpace; } > const UnnamedType& elementType() const { return m_elementType; } >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp b/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp >index 38e7a71876ee850b0d758945ad1971fec91fd6e0..69dffdfe5a5c413e118753c38d1d39c014c8082f 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp >+++ b/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp >@@ -63,21 +63,6 @@ static String mapFunctionName(String& functionName) > return functionName; > } > >-static String convertAddressSpace(AST::AddressSpace addressSpace) >-{ >- switch (addressSpace) { >- case AST::AddressSpace::Constant: >- return "constant"_str; >- case AST::AddressSpace::Device: >- return "device"_str; >- case AST::AddressSpace::Threadgroup: >- return "threadgroup"_str; >- default: >- ASSERT(addressSpace == AST::AddressSpace::Thread); >- return "thread"_str; >- } >-} >- > static String atomicName(String input) > { > if (input == "Add") >@@ -375,7 +360,7 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara > auto& fourthArgumentPointer = downcast<AST::PointerType>(*nativeFunctionDeclaration.parameters()[3]->type()); > auto fourthArgumentAddressSpace = fourthArgumentPointer.addressSpace(); > auto fourthArgumentPointee = typeNamer.mangledNameForType(fourthArgumentPointer.elementType()); >- stringBuilder.append(makeString("void ", outputFunctionName, '(', convertAddressSpace(firstArgumentAddressSpace), ' ', firstArgumentPointee, "* object, ", secondArgument, " compare, ", thirdArgument, " desired, ", convertAddressSpace(fourthArgumentAddressSpace), ' ', fourthArgumentPointee, "* out) {\n")); >+ stringBuilder.append(makeString("void ", outputFunctionName, '(', toString(firstArgumentAddressSpace), ' ', firstArgumentPointee, "* object, ", secondArgument, " compare, ", thirdArgument, " desired, ", toString(fourthArgumentAddressSpace), ' ', fourthArgumentPointee, "* out) {\n")); > stringBuilder.append(" atomic_compare_exchange_weak_explicit(object, &compare, desired, memory_order_relaxed);\n"); > stringBuilder.append(" *out = compare;\n"); > stringBuilder.append("}\n"); >@@ -393,7 +378,7 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara > auto thirdArgumentAddressSpace = thirdArgumentPointer.addressSpace(); > auto thirdArgumentPointee = typeNamer.mangledNameForType(thirdArgumentPointer.elementType()); > auto name = atomicName(nativeFunctionDeclaration.name().substring("Interlocked"_str.length())); >- stringBuilder.append(makeString("void ", outputFunctionName, '(', convertAddressSpace(firstArgumentAddressSpace), ' ', firstArgumentPointee, "* object, ", secondArgument, " operand, ", convertAddressSpace(thirdArgumentAddressSpace), ' ', thirdArgumentPointee, "* out) {\n")); >+ stringBuilder.append(makeString("void ", outputFunctionName, '(', toString(firstArgumentAddressSpace), ' ', firstArgumentPointee, "* object, ", secondArgument, " operand, ", toString(thirdArgumentAddressSpace), ' ', thirdArgumentPointee, "* out) {\n")); > stringBuilder.append(makeString(" *out = atomic_fetch_", name, "_explicit(object, operand, memory_order_relaxed);\n")); > stringBuilder.append("}\n"); > return stringBuilder.toString(); >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp >index 75578a49b29a894ddf70211d6e5e1ce9775ae7ac..dbcb7a91453bb0ae065713e58c9866dfcea72880 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp >@@ -36,6 +36,7 @@ > #include "WHLSLDereferenceExpression.h" > #include "WHLSLDoWhileLoop.h" > #include "WHLSLDotExpression.h" >+#include "WHLSLEntryPointType.h" > #include "WHLSLForLoop.h" > #include "WHLSLGatherEntryPointItems.h" > #include "WHLSLIfStatement.h" >@@ -491,6 +492,8 @@ private: > void visit(AST::TernaryExpression&) override; > void visit(AST::CallExpression&) override; > >+ void finishVisiting(AST::PropertyAccessExpression&, ResolvingType* additionalArgumentType = nullptr); >+ > HashMap<AST::Expression*, ResolvingType> m_typeMap; > HashMap<AST::Expression*, AST::TypeAnnotation> m_typeAnnotations; > HashSet<String> m_vertexEntryPoints; >@@ -966,9 +969,9 @@ void Checker::visit(AST::MakeArrayReferenceExpression& makeArrayReferenceExpress > assignType(makeArrayReferenceExpression, makeUniqueRef<AST::ArrayReferenceType>(Lexer::Token(makeArrayReferenceExpression.origin()), *leftAddressSpace, leftValueType->clone())); > } > >-void Checker::visit(AST::DotExpression& dotExpression) >+void Checker::finishVisiting(AST::PropertyAccessExpression& propertyAccessExpression, ResolvingType* additionalArgumentType) > { >- auto baseInfo = recurseAndGetInfo(dotExpression.base()); >+ auto baseInfo = recurseAndGetInfo(propertyAccessExpression.base()); > if (!baseInfo) > return; > auto baseUnnamedType = commit(baseInfo->resolvingType); >@@ -979,65 +982,89 @@ void Checker::visit(AST::DotExpression& dotExpression) > AST::UnnamedType* getterReturnType = nullptr; > { > Vector<std::reference_wrapper<ResolvingType>> getterArgumentTypes { baseInfo->resolvingType }; >- getterFunction = resolveFunctionOverloadImpl(dotExpression.possibleGetterOverloads(), getterArgumentTypes, nullptr); >- if (getterFunction) >+ if (additionalArgumentType) >+ getterArgumentTypes.append(*additionalArgumentType); >+ if ((getterFunction = resolveFunctionOverloadImpl(propertyAccessExpression.possibleGetterOverloads(), getterArgumentTypes, nullptr))) > getterReturnType = &getterFunction->type(); > } > > AST::FunctionDeclaration* anderFunction = nullptr; > AST::UnnamedType* anderReturnType = nullptr; >- if (auto leftAddressSpace = baseInfo->typeAnnotation.leftAddressSpace()) { >- auto argumentType = makeUniqueRef<AST::PointerType>(Lexer::Token(dotExpression.origin()), *leftAddressSpace, baseUnnamedType->get().clone()); >- Vector<std::reference_wrapper<ResolvingType>> anderArgumentTypes { baseInfo->resolvingType }; >- anderFunction = resolveFunctionOverloadImpl(dotExpression.possibleAnderOverloads(), anderArgumentTypes, nullptr); >- if (anderFunction) >+ auto leftAddressSpace = baseInfo->typeAnnotation.leftAddressSpace(); >+ if (leftAddressSpace) { >+ ResolvingType argumentType = { makeUniqueRef<AST::PointerType>(Lexer::Token(propertyAccessExpression.origin()), *leftAddressSpace, baseUnnamedType->get().clone()) }; >+ Vector<std::reference_wrapper<ResolvingType>> anderArgumentTypes { argumentType }; >+ if (additionalArgumentType) >+ anderArgumentTypes.append(*additionalArgumentType); >+ if ((anderFunction = resolveFunctionOverloadImpl(propertyAccessExpression.possibleAnderOverloads(), anderArgumentTypes, nullptr))) > anderReturnType = &downcast<AST::PointerType>(anderFunction->type()).elementType(); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198164 Enforce the return of anders will always be a pointer > } > > AST::FunctionDeclaration* threadAnderFunction = nullptr; > AST::UnnamedType* threadAnderReturnType = nullptr; > { >- auto argumentType = makeUniqueRef<AST::PointerType>(Lexer::Token(dotExpression.origin()), AST::AddressSpace::Thread, baseUnnamedType->get().clone()); >- Vector<std::reference_wrapper<ResolvingType>> threadAnderArgumentTypes { baseInfo->resolvingType }; >- threadAnderFunction = resolveFunctionOverloadImpl(dotExpression.possibleAnderOverloads(), threadAnderArgumentTypes, nullptr); >- if (threadAnderFunction) >+ ResolvingType argumentType = { makeUniqueRef<AST::PointerType>(Lexer::Token(propertyAccessExpression.origin()), AST::AddressSpace::Thread, baseUnnamedType->get().clone()) }; >+ Vector<std::reference_wrapper<ResolvingType>> threadAnderArgumentTypes { argumentType }; >+ if (additionalArgumentType) >+ threadAnderArgumentTypes.append(*additionalArgumentType); >+ if ((threadAnderFunction = resolveFunctionOverloadImpl(propertyAccessExpression.possibleAnderOverloads(), threadAnderArgumentTypes, nullptr))) > threadAnderReturnType = &downcast<AST::PointerType>(threadAnderFunction->type()).elementType(); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198164 Enforce the return of anders will always be a pointer > } > >- if (!getterFunction && !anderFunction) { >+ if (leftAddressSpace && !anderFunction && !getterFunction) { >+ setError(); >+ return; >+ } >+ >+ if (!leftAddressSpace && !threadAnderFunction && !getterFunction) { > setError(); > return; > } >- if (getterFunction && anderFunction) { >+ >+ if (threadAnderFunction && getterFunction) { > setError(); > return; > } >+ > if (anderFunction && threadAnderFunction && !matches(*anderReturnType, *threadAnderReturnType)) { > setError(); > return; > } > >- AST::UnnamedType* fieldType = getterReturnType ? getterReturnType : anderReturnType; >+ if (getterFunction && anderFunction && !matches(*getterReturnType, *anderReturnType)) { >+ setError(); >+ return; >+ } >+ >+ if (getterFunction && threadAnderFunction && !matches(*getterReturnType, *threadAnderReturnType)) { >+ setError(); >+ return; >+ } >+ >+ AST::UnnamedType* fieldType = getterReturnType ? getterReturnType : anderReturnType ? anderReturnType : threadAnderReturnType; > > AST::FunctionDeclaration* setterFunction = nullptr; > AST::UnnamedType* setterReturnType = nullptr; > { > ResolvingType fieldResolvingType(fieldType->clone()); >- Vector<std::reference_wrapper<ResolvingType>> setterArgumentTypes { baseInfo->resolvingType, fieldResolvingType }; >- setterFunction = resolveFunctionOverloadImpl(dotExpression.possibleSetterOverloads(), setterArgumentTypes, nullptr); >+ Vector<std::reference_wrapper<ResolvingType>> setterArgumentTypes { baseInfo->resolvingType }; >+ if (additionalArgumentType) >+ setterArgumentTypes.append(*additionalArgumentType); >+ setterArgumentTypes.append(fieldResolvingType); >+ setterFunction = resolveFunctionOverloadImpl(propertyAccessExpression.possibleSetterOverloads(), setterArgumentTypes, nullptr); > if (setterFunction) > setterReturnType = &setterFunction->type(); > } > >- if (setterFunction && anderFunction) { >+ if (setterFunction && !getterFunction) { > setError(); > return; > } > >- dotExpression.setGetterFunction(getterFunction); >- dotExpression.setAnderFunction(anderFunction); >- dotExpression.setThreadAnderFunction(threadAnderFunction); >- dotExpression.setSetterFunction(setterFunction); >+ propertyAccessExpression.setGetterFunction(getterFunction); >+ propertyAccessExpression.setAnderFunction(anderFunction); >+ propertyAccessExpression.setThreadAnderFunction(threadAnderFunction); >+ propertyAccessExpression.setSetterFunction(setterFunction); > > AST::TypeAnnotation typeAnnotation = AST::RightValue(); > if (auto leftAddressSpace = baseInfo->typeAnnotation.leftAddressSpace()) { >@@ -1045,14 +1072,22 @@ void Checker::visit(AST::DotExpression& dotExpression) > typeAnnotation = AST::LeftValue { *leftAddressSpace }; > else if (setterFunction) > typeAnnotation = AST::AbstractLeftValue(); >- } else if (!baseInfo->typeAnnotation.isRightValue() && (setterFunction || anderFunction)) >+ } else if (!baseInfo->typeAnnotation.isRightValue() && (setterFunction || threadAnderFunction)) > typeAnnotation = AST::AbstractLeftValue(); >- assignType(dotExpression, fieldType->clone(), WTFMove(typeAnnotation)); >+ assignType(propertyAccessExpression, fieldType->clone(), WTFMove(typeAnnotation)); > } > >-void Checker::visit(AST::IndexExpression&) >+void Checker::visit(AST::DotExpression& dotExpression) >+{ >+ finishVisiting(dotExpression); >+} >+ >+void Checker::visit(AST::IndexExpression& indexExpression) > { >- // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198163 Implement this. >+ auto baseInfo = recurseAndGetInfo(indexExpression.indexExpression()); >+ if (!baseInfo) >+ return; >+ finishVisiting(indexExpression, &baseInfo->resolvingType); > } > > void Checker::visit(AST::VariableReference& variableReference) >@@ -1362,7 +1397,7 @@ void Checker::visit(AST::CommaExpression& commaExpression) > if (error()) > return; > auto lastInfo = getInfo(commaExpression.list().last()); >- forwardType(commaExpression, lastInfo->resolvingType, lastInfo->typeAnnotation); >+ forwardType(commaExpression, lastInfo->resolvingType); > } > > void Checker::visit(AST::TernaryExpression& ternaryExpression) >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLInferTypes.h b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLInferTypes.h >index 173d3014497d2a3742e80670f80bc96ff0f79c4d..19fb1ffcf814414cd6a227dea8943055028eb0ac 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLInferTypes.h >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLInferTypes.h >@@ -47,7 +47,6 @@ class UnnamedType; > bool matches(const AST::UnnamedType&, const AST::UnnamedType&); > bool matches(const AST::NamedType&, const AST::NamedType&); > bool matches(const AST::UnnamedType&, const AST::NamedType&); >-// FIXME: Is anyone actually using the return type here? > Optional<UniqueRef<AST::UnnamedType>> matchAndCommit(AST::UnnamedType&, AST::ResolvableType&); > Optional<UniqueRef<AST::UnnamedType>> matchAndCommit(AST::NamedType&, AST::ResolvableType&); > Optional<UniqueRef<AST::UnnamedType>> matchAndCommit(AST::ResolvableType&, AST::ResolvableType&); >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp >index fa069cabce204d379ef6568e7d926073792f85e7..88ad81f06c4b8c2fd432f99aee718c0f67950475 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp >@@ -51,10 +51,11 @@ 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; > >- bool simplifyRightValue(AST::DotExpression&); >+ bool simplifyRightValue(AST::PropertyAccessExpression&, Optional<UniqueRef<AST::Expression>>&& additionalArgument); > bool simplifyAbstractLeftValue(AST::AssignmentExpression&, AST::DotExpression&, UniqueRef<AST::Expression>&& right); > void simplifyLeftValue(AST::Expression&); > >@@ -64,7 +65,15 @@ private: > void PropertyResolver::visit(AST::DotExpression& dotExpression) > { > // Unless we're inside an AssignmentExpression or a ReadModifyWriteExpression, we're a right value. >- if (!simplifyRightValue(dotExpression)) >+ if (!simplifyRightValue(dotExpression, WTF::nullopt)) >+ setError(); >+} >+ >+void PropertyResolver::visit(AST::IndexExpression& indexExpression) >+{ >+ checkErrorAndVisit(indexExpression.indexExpression()); >+ // Unless we're inside an AssignmentExpression or a ReadModifyWriteExpression, we're a right value. >+ if (!simplifyRightValue(indexExpression, indexExpression.takeIndex())) > setError(); > } > >@@ -75,79 +84,105 @@ void PropertyResolver::visit(AST::FunctionDefinition& functionDefinition) > functionDefinition.block().statements().insert(0, makeUniqueRef<AST::VariableDeclarationsStatement>(Lexer::Token(m_variableDeclarations[0]->origin()), WTFMove(m_variableDeclarations))); > } > >-static Optional<UniqueRef<AST::Expression>> setterCall(AST::DotExpression& dotExpression, UniqueRef<AST::Expression>&& newValue, const std::function<UniqueRef<AST::Expression>()>& leftValueFactory, const std::function<UniqueRef<AST::Expression>()>& pointerToLeftValueFactory) >+static Optional<UniqueRef<AST::Expression>> setterCall(AST::PropertyAccessExpression& propertyAccessExpression, AST::FunctionDeclaration* relevantAnder, UniqueRef<AST::Expression>&& newValue, const std::function<UniqueRef<AST::Expression>()>& leftValueFactory, const std::function<UniqueRef<AST::Expression>()>& pointerToLeftValueFactory, AST::VariableDeclaration* indexVariable) > { >- if (dotExpression.anderFunction()) { >+ if (relevantAnder) { > // *operator&.foo(&v) = newValue >- if (!dotExpression.threadAnderFunction()) >- return WTF::nullopt; >- > Vector<UniqueRef<AST::Expression>> arguments; > arguments.append(pointerToLeftValueFactory()); >- auto callExpression = makeUniqueRef<AST::CallExpression>(Lexer::Token(dotExpression.origin()), String(dotExpression.threadAnderFunction()->name()), WTFMove(arguments)); >- callExpression->setType(dotExpression.threadAnderFunction()->type().clone()); >+ if (indexVariable) { >+ 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 callExpression = makeUniqueRef<AST::CallExpression>(Lexer::Token(propertyAccessExpression.origin()), String(relevantAnder->name()), WTFMove(arguments)); >+ callExpression->setType(relevantAnder->type().clone()); > callExpression->setTypeAnnotation(AST::RightValue()); >- callExpression->setFunction(*dotExpression.threadAnderFunction()); >+ callExpression->setFunction(*relevantAnder); > >- auto dereferenceExpression = makeUniqueRef<AST::DereferenceExpression>(Lexer::Token(dotExpression.origin()), WTFMove(callExpression)); >- dereferenceExpression->setType(downcast<AST::PointerType>(dotExpression.threadAnderFunction()->type()).elementType().clone()); >+ auto dereferenceExpression = makeUniqueRef<AST::DereferenceExpression>(Lexer::Token(propertyAccessExpression.origin()), WTFMove(callExpression)); >+ dereferenceExpression->setType(downcast<AST::PointerType>(relevantAnder->type()).elementType().clone()); > dereferenceExpression->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); > >- auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(Lexer::Token(dotExpression.origin()), WTFMove(dereferenceExpression), WTFMove(newValue)); >- assignmentExpression->setType(downcast<AST::PointerType>(dotExpression.threadAnderFunction()->type()).elementType().clone()); >+ auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(Lexer::Token(propertyAccessExpression.origin()), 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(dotExpression.setterFunction()); >+ ASSERT(propertyAccessExpression.setterFunction()); > > Vector<UniqueRef<AST::Expression>> arguments; > arguments.append(leftValueFactory()); >+ if (indexVariable) { >+ 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)); >+ } > arguments.append(WTFMove(newValue)); >- auto callExpression = makeUniqueRef<AST::CallExpression>(Lexer::Token(dotExpression.origin()), String(dotExpression.setterFunction()->name()), WTFMove(arguments)); >- callExpression->setType(dotExpression.setterFunction()->type().clone()); >+ >+ auto callExpression = makeUniqueRef<AST::CallExpression>(Lexer::Token(propertyAccessExpression.origin()), String(propertyAccessExpression.setterFunction()->name()), WTFMove(arguments)); >+ callExpression->setType(propertyAccessExpression.setterFunction()->type().clone()); > callExpression->setTypeAnnotation(AST::RightValue()); >- callExpression->setFunction(*dotExpression.setterFunction()); >+ callExpression->setFunction(*propertyAccessExpression.setterFunction()); > >- auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(Lexer::Token(dotExpression.origin()), leftValueFactory(), WTFMove(callExpression)); >- assignmentExpression->setType(dotExpression.setterFunction()->type().clone()); >+ auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(Lexer::Token(propertyAccessExpression.origin()), 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::DotExpression& dotExpression, const std::function<UniqueRef<AST::Expression>()>& leftValueFactory, const std::function<UniqueRef<AST::Expression>()>& pointerToLeftValueFactory) >+static Optional<UniqueRef<AST::Expression>> getterCall(AST::PropertyAccessExpression& propertyAccessExpression, AST::FunctionDeclaration* relevantAnder, const std::function<UniqueRef<AST::Expression>()>& leftValueFactory, const std::function<UniqueRef<AST::Expression>()>& pointerToLeftValueFactory, AST::VariableDeclaration* indexVariable) > { >- if (dotExpression.anderFunction()) { >+ if (relevantAnder) { > // *operator&.foo(&v) >- if (!dotExpression.threadAnderFunction()) >- return WTF::nullopt; >- > Vector<UniqueRef<AST::Expression>> arguments; > arguments.append(pointerToLeftValueFactory()); >- auto callExpression = makeUniqueRef<AST::CallExpression>(Lexer::Token(dotExpression.origin()), String(dotExpression.threadAnderFunction()->name()), WTFMove(arguments)); >- callExpression->setType(dotExpression.threadAnderFunction()->type().clone()); >+ if (indexVariable) { >+ 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 callExpression = makeUniqueRef<AST::CallExpression>(Lexer::Token(propertyAccessExpression.origin()), String(relevantAnder->name()), WTFMove(arguments)); >+ callExpression->setType(relevantAnder->type().clone()); > callExpression->setTypeAnnotation(AST::RightValue()); >- callExpression->setFunction(*dotExpression.threadAnderFunction()); >+ callExpression->setFunction(*relevantAnder); > >- auto dereferenceExpression = makeUniqueRef<AST::DereferenceExpression>(Lexer::Token(dotExpression.origin()), WTFMove(callExpression)); >- dereferenceExpression->setType(downcast<AST::PointerType>(dotExpression.threadAnderFunction()->type()).elementType().clone()); >+ auto dereferenceExpression = makeUniqueRef<AST::DereferenceExpression>(Lexer::Token(propertyAccessExpression.origin()), 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(dotExpression.getterFunction()); >+ ASSERT(propertyAccessExpression.getterFunction()); > > Vector<UniqueRef<AST::Expression>> arguments; > arguments.append(leftValueFactory()); >- auto callExpression = makeUniqueRef<AST::CallExpression>(Lexer::Token(dotExpression.origin()), String(dotExpression.getterFunction()->name()), WTFMove(arguments)); >- callExpression->setType(dotExpression.getterFunction()->type().clone()); >+ if (indexVariable) { >+ 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 callExpression = makeUniqueRef<AST::CallExpression>(Lexer::Token(propertyAccessExpression.origin()), String(propertyAccessExpression.getterFunction()->name()), WTFMove(arguments)); >+ callExpression->setType(propertyAccessExpression.getterFunction()->type().clone()); > callExpression->setTypeAnnotation(AST::RightValue()); >- callExpression->setFunction(*dotExpression.getterFunction()); >+ callExpression->setFunction(*propertyAccessExpression.getterFunction()); > > return UniqueRef<AST::Expression>(WTFMove(callExpression)); > } >@@ -161,7 +196,7 @@ struct ModificationResult { > Vector<UniqueRef<AST::Expression>> expressions; > UniqueRef<AST::Expression> result; > }; >-static Optional<ModifyResult> modify(AST::DotExpression& dotExpression, std::function<Optional<ModificationResult>(Optional<UniqueRef<AST::Expression>>&&)> modification) >+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: >@@ -181,22 +216,22 @@ static Optional<ModifyResult> modify(AST::DotExpression& dotExpression, std::fun > // r = operator.d=(r, newValue); > // q = operator.c=(q, r); > // >- // Step 4: >+ // 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::DotExpression>> chain; >- AST::DotExpression* iterator = &dotExpression; >+ 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()); >- ASSERT(is<AST::DotExpression>(iterator->base())); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198163 Make this work with index expressions >- iterator = &downcast<AST::DotExpression>(iterator->base()); >+ ASSERT(is<AST::PropertyAccessExpression>(iterator->base())); >+ iterator = &downcast<AST::PropertyAccessExpression>(iterator->base()); > } > auto leftExpression = iterator->takeBase(); > AST::Expression& innerLeftExpression = leftExpression; >@@ -208,8 +243,29 @@ static Optional<ModifyResult> modify(AST::DotExpression& dotExpression, std::fun > Vector<UniqueRef<AST::VariableDeclaration>> intermediateVariables; > intermediateVariables.reserveInitialCapacity(chain.size() - 1); > for (size_t i = 1; i < chain.size(); ++i) { >- auto& dotExpression = static_cast<AST::DotExpression&>(chain[i]); >- intermediateVariables.uncheckedAppend(makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(dotExpression.origin()), AST::Qualifiers(), dotExpression.resolvedType().clone(), String(), WTF::nullopt, WTF::nullopt)); >+ auto& propertyAccessExpression = static_cast<AST::PropertyAccessExpression&>(chain[i]); >+ intermediateVariables.uncheckedAppend(makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(propertyAccessExpression.origin()), AST::Qualifiers(), propertyAccessExpression.resolvedType().clone(), String(), WTF::nullopt, WTF::nullopt)); >+ } >+ >+ // 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). >+ 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); >+ intermediateVariables.uncheckedAppend(makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(propertyAccessExpression.origin()), AST::Qualifiers(), indexExpression.indexExpression().resolvedType().clone(), String(), WTF::nullopt, WTF::nullopt)); > } > > Vector<UniqueRef<AST::Expression>> expressions; >@@ -248,7 +304,7 @@ static Optional<ModifyResult> modify(AST::DotExpression& dotExpression, std::fun > 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>(Lexer::Token(dotExpression.origin()), WTFMove(variableReference)); >+ auto dereferenceExpression = makeUniqueRef<AST::DereferenceExpression>(Lexer::Token(propertyAccessExpression.origin()), WTFMove(variableReference)); > ASSERT(pointerVariable->type()); > dereferenceExpression->setType(downcast<AST::PointerType>(*pointerVariable->type()).elementType().clone()); > dereferenceExpression->setTypeAnnotation(AST::LeftValue { downcast<AST::PointerType>(*pointerVariable->type()).addressSpace() }); >@@ -261,9 +317,9 @@ static Optional<ModifyResult> modify(AST::DotExpression& dotExpression, std::fun > 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? > >- auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(Lexer::Token(dotExpression.origin()), WTFMove(variableReference)); >+ auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(Lexer::Token(propertyAccessExpression.origin()), WTFMove(variableReference)); > ASSERT(previous->type()); >- makePointerExpression->setType(makeUniqueRef<AST::PointerType>(Lexer::Token(dotExpression.origin()), AST::AddressSpace::Thread, previous->type()->clone())); >+ makePointerExpression->setType(makeUniqueRef<AST::PointerType>(Lexer::Token(propertyAccessExpression.origin()), AST::AddressSpace::Thread, previous->type()->clone())); > makePointerExpression->setTypeAnnotation(AST::RightValue()); > return makePointerExpression; > } >@@ -274,11 +330,32 @@ static Optional<ModifyResult> modify(AST::DotExpression& dotExpression, std::fun > variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? > return variableReference; > }; >+ auto appendIndexAssignment = [&](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>(Lexer::Token(propertyAccessExpression.origin()), 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::DotExpression& dotExpression = chain[i]; >+ AST::PropertyAccessExpression& propertyAccessExpression = chain[i]; > AST::VariableDeclaration& variableDeclaration = intermediateVariables[i - 1]; >+ Optional<UniqueRef<AST::VariableDeclaration>>& indexVariable = indexVariables[i]; >+ >+ appendIndexAssignment(indexVariable); > >- auto callExpression = getterCall(dotExpression, previousLeftValue, pointerToPreviousLeftValue); >+ AST::FunctionDeclaration* relevantAnder = i == chain.size() - 1 ? propertyAccessExpression.anderFunction() : propertyAccessExpression.threadAnderFunction(); >+ auto callExpression = getterCall(propertyAccessExpression, relevantAnder, previousLeftValue, pointerToPreviousLeftValue, indexVariable ? &*indexVariable : nullptr); > > if (!callExpression) > return WTF::nullopt; >@@ -288,7 +365,7 @@ static Optional<ModifyResult> modify(AST::DotExpression& dotExpression, std::fun > 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>(Lexer::Token(dotExpression.origin()), WTFMove(variableReference), WTFMove(*callExpression)); >+ auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(Lexer::Token(propertyAccessExpression.origin()), WTFMove(variableReference), WTFMove(*callExpression)); > assignmentExpression->setType(variableDeclaration.type()->clone()); > assignmentExpression->setTypeAnnotation(AST::RightValue()); > >@@ -296,7 +373,9 @@ static Optional<ModifyResult> modify(AST::DotExpression& dotExpression, std::fun > > previous = &variableDeclaration; > } >- auto lastGetterCallExpression = getterCall(chain[0], previousLeftValue, pointerToPreviousLeftValue); >+ appendIndexAssignment(indexVariables[0]); >+ AST::FunctionDeclaration* relevantAnder = chain.size() == 1 ? propertyAccessExpression.anderFunction() : propertyAccessExpression.threadAnderFunction(); >+ auto lastGetterCallExpression = getterCall(chain[0], relevantAnder, previousLeftValue, pointerToPreviousLeftValue, indexVariables[0] ? &*(indexVariables[0]) : nullptr); > > // Step 3: > auto modificationResult = modification(WTFMove(lastGetterCallExpression)); >@@ -309,10 +388,11 @@ static Optional<ModifyResult> modify(AST::DotExpression& dotExpression, std::fun > UniqueRef<AST::Expression> rightValue = WTFMove(modificationResult->result); > auto expressionType = rightValue->resolvedType().clone(); > for (size_t i = 0; i < chain.size() - 1; ++i) { >- AST::DotExpression& dotExpression = chain[i]; >+ AST::PropertyAccessExpression& propertyAccessExpression = chain[i]; > AST::VariableDeclaration& variableDeclaration = intermediateVariables[i]; >+ Optional<UniqueRef<AST::VariableDeclaration>>& indexVariable = indexVariables[i]; > >- auto assignmentExpression = setterCall(dotExpression, WTFMove(rightValue), [&]() -> UniqueRef<AST::Expression> { >+ 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()); >@@ -324,12 +404,12 @@ static Optional<ModifyResult> modify(AST::DotExpression& dotExpression, std::fun > 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 makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(Lexer::Token(dotExpression.origin()), WTFMove(variableReference)); >+ auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(Lexer::Token(propertyAccessExpression.origin()), WTFMove(variableReference)); > ASSERT(variableDeclaration.type()); >- makePointerExpression->setType(makeUniqueRef<AST::PointerType>(Lexer::Token(dotExpression.origin()), AST::AddressSpace::Thread, variableDeclaration.type()->clone())); >+ makePointerExpression->setType(makeUniqueRef<AST::PointerType>(Lexer::Token(propertyAccessExpression.origin()), AST::AddressSpace::Thread, variableDeclaration.type()->clone())); > makePointerExpression->setTypeAnnotation(AST::RightValue()); > return makePointerExpression; >- }); >+ }, indexVariable ? &*indexVariable : nullptr); > > if (!assignmentExpression) > return WTF::nullopt; >@@ -344,13 +424,14 @@ static Optional<ModifyResult> modify(AST::DotExpression& dotExpression, std::fun > > // Step 5: > { >- auto assignmentExpression = setterCall(chain[chain.size() - 1], WTFMove(rightValue), [&]() -> UniqueRef<AST::Expression> { >+ 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>(Lexer::Token(dotExpression.origin()), WTFMove(variableReference)); >+ auto dereferenceExpression = makeUniqueRef<AST::DereferenceExpression>(Lexer::Token(propertyAccessExpression.origin()), WTFMove(variableReference)); > ASSERT(pointerVariable->type()); > dereferenceExpression->setType(downcast<AST::PointerType>(*pointerVariable->type()).elementType().clone()); > dereferenceExpression->setTypeAnnotation(AST::LeftValue { downcast<AST::PointerType>(*pointerVariable->type()).addressSpace() }); >@@ -361,7 +442,7 @@ static Optional<ModifyResult> modify(AST::DotExpression& dotExpression, std::fun > 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? > return variableReference; >- }); >+ }, indexVariables[indexVariables.size() - 1] ? &*(indexVariables[indexVariables.size() - 1]) : nullptr); > > if (!assignmentExpression) > return WTF::nullopt; >@@ -385,8 +466,8 @@ void PropertyResolver::visit(AST::AssignmentExpression& assignmentExpression) > return; > } > ASSERT(!assignmentExpression.left().typeAnnotation().isRightValue()); >- if (!is<AST::DotExpression>(assignmentExpression.left())) { >- setError(); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198163 Make this work with index expressions. >+ if (!is<AST::PropertyAccessExpression>(assignmentExpression.left())) { >+ setError(); > return; > } > >@@ -394,7 +475,7 @@ void PropertyResolver::visit(AST::AssignmentExpression& assignmentExpression) > > checkErrorAndVisit(assignmentExpression.right()); > >- auto modifyResult = modify(downcast<AST::DotExpression>(assignmentExpression.left()), [&](Optional<UniqueRef<AST::Expression>>&&) -> Optional<ModificationResult> { >+ auto modifyResult = modify(downcast<AST::PropertyAccessExpression>(assignmentExpression.left()), [&](Optional<UniqueRef<AST::Expression>>&&) -> Optional<ModificationResult> { > return {{ Vector<UniqueRef<AST::Expression>>(), assignmentExpression.takeRight() }}; > }); > >@@ -424,6 +505,8 @@ void PropertyResolver::visit(AST::ReadModifyWriteExpression& readModifyWriteExpr > // newValue = ...; > // *p = newValue; > >+ simplifyLeftValue(readModifyWriteExpression.leftValue()); >+ > auto baseType = readModifyWriteExpression.leftValue().resolvedType().clone(); > auto pointerType = makeUniqueRef<AST::PointerType>(Lexer::Token(readModifyWriteExpression.leftValue().origin()), *readModifyWriteExpression.leftValue().typeAnnotation().leftAddressSpace(), baseType->clone()); > >@@ -520,11 +603,11 @@ void PropertyResolver::visit(AST::ReadModifyWriteExpression& readModifyWriteExpr > } > > ASSERT(!readModifyWriteExpression.leftValue().typeAnnotation().isRightValue()); >- if (!is<AST::DotExpression>(readModifyWriteExpression.leftValue())) { >- setError(); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198163 Make this work with index expressions. >+ if (!is<AST::PropertyAccessExpression>(readModifyWriteExpression.leftValue())) { >+ setError(); > return; > } >- auto modifyResult = modify(downcast<AST::DotExpression>(readModifyWriteExpression.leftValue()), [&](Optional<UniqueRef<AST::Expression>>&& lastGetterCallExpression) -> Optional<ModificationResult> { >+ 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; >@@ -581,128 +664,150 @@ void PropertyResolver::visit(AST::ReadModifyWriteExpression& readModifyWriteExpr > m_variableDeclarations.append(WTFMove(newVariableDeclaration)); > } > >-bool PropertyResolver::simplifyRightValue(AST::DotExpression& dotExpression) >+bool PropertyResolver::simplifyRightValue(AST::PropertyAccessExpression& propertyAccessExpression, Optional<UniqueRef<AST::Expression>>&& additionalArgument) > { >- Lexer::Token origin = dotExpression.origin(); >+ Lexer::Token origin = propertyAccessExpression.origin(); > >- checkErrorAndVisit(dotExpression.base()); >+ checkErrorAndVisit(propertyAccessExpression.base()); > >- if (auto* anderFunction = dotExpression.anderFunction()) { >- auto& base = dotExpression.base(); >- if (auto leftAddressSpace = base.typeAnnotation().leftAddressSpace()) { >- auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(Lexer::Token(origin), dotExpression.takeBase()); >+ auto& base = propertyAccessExpression.base(); >+ if (auto leftAddressSpace = base.typeAnnotation().leftAddressSpace()) { >+ if (auto* anderFunction = propertyAccessExpression.anderFunction()) { >+ auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(Lexer::Token(origin), propertyAccessExpression.takeBase()); > makePointerExpression->setType(makeUniqueRef<AST::PointerType>(Lexer::Token(origin), *leftAddressSpace, base.resolvedType().clone())); > makePointerExpression->setTypeAnnotation(AST::RightValue()); > > Vector<UniqueRef<AST::Expression>> arguments; > arguments.append(WTFMove(makePointerExpression)); >+ if (additionalArgument) >+ arguments.append(WTFMove(*additionalArgument)); > auto callExpression = makeUniqueRef<AST::CallExpression>(Lexer::Token(origin), String(anderFunction->name()), WTFMove(arguments)); > callExpression->setType(anderFunction->type().clone()); > callExpression->setTypeAnnotation(AST::RightValue()); > callExpression->setFunction(*anderFunction); > >- auto* dereferenceExpression = AST::replaceWith<AST::DereferenceExpression>(dotExpression, WTFMove(origin), WTFMove(callExpression)); >+ auto* dereferenceExpression = AST::replaceWith<AST::DereferenceExpression>(propertyAccessExpression, WTFMove(origin), WTFMove(callExpression)); > dereferenceExpression->setType(downcast<AST::PointerType>(anderFunction->type()).elementType().clone()); > dereferenceExpression->setTypeAnnotation(AST::LeftValue { downcast<AST::PointerType>(anderFunction->type()).addressSpace() }); > return true; > } >+ } > >- // We have an ander, but no left value to call it on. Let's save the value into a temporary variable to create a left value. >- // This is effectively inlining the functions the spec says are generated. >- if (!dotExpression.threadAnderFunction()) >- return false; >+ if (propertyAccessExpression.getterFunction()) { >+ auto& getterFunction = *propertyAccessExpression.getterFunction(); >+ Vector<UniqueRef<AST::Expression>> arguments; >+ arguments.append(propertyAccessExpression.takeBase()); >+ if (additionalArgument) >+ arguments.append(WTFMove(*additionalArgument)); >+ auto* callExpression = AST::replaceWith<AST::CallExpression>(propertyAccessExpression, WTFMove(origin), String(getterFunction.name()), WTFMove(arguments)); >+ callExpression->setFunction(getterFunction); >+ callExpression->setType(getterFunction.type().clone()); >+ callExpression->setTypeAnnotation(AST::RightValue()); >+ return true; >+ } > >- auto variableDeclaration = makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(origin), AST::Qualifiers(), base.resolvedType().clone(), String(), WTF::nullopt, WTF::nullopt); >+ // We have an ander, but no left value to call it on. Let's save the value into a temporary variable to create a left value. >+ // This is effectively inlining the functions the spec says are generated. >+ ASSERT(propertyAccessExpression.threadAnderFunction()); >+ auto* threadAnderFunction = propertyAccessExpression.threadAnderFunction(); > >- auto variableReference1 = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(variableDeclaration)); >- variableReference1->setType(base.resolvedType().clone()); >- variableReference1->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); >+ auto variableDeclaration = makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(origin), AST::Qualifiers(), base.resolvedType().clone(), String(), WTF::nullopt, WTF::nullopt); > >- auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(Lexer::Token(origin), WTFMove(variableReference1), dotExpression.takeBase()); >- assignmentExpression->setType(base.resolvedType().clone()); >- assignmentExpression->setTypeAnnotation(AST::RightValue()); >+ auto variableReference1 = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(variableDeclaration)); >+ variableReference1->setType(base.resolvedType().clone()); >+ variableReference1->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); > >- auto variableReference2 = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(variableDeclaration)); >- variableReference2->setType(base.resolvedType().clone()); >- variableReference2->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); >+ auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(Lexer::Token(origin), WTFMove(variableReference1), propertyAccessExpression.takeBase()); >+ assignmentExpression->setType(base.resolvedType().clone()); >+ assignmentExpression->setTypeAnnotation(AST::RightValue()); > >- auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(Lexer::Token(origin), WTFMove(variableReference2)); >- makePointerExpression->setType(makeUniqueRef<AST::PointerType>(Lexer::Token(origin), AST::AddressSpace::Thread, base.resolvedType().clone())); >- makePointerExpression->setTypeAnnotation(AST::RightValue()); >+ auto variableReference2 = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(variableDeclaration)); >+ variableReference2->setType(base.resolvedType().clone()); >+ variableReference2->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); > >- Vector<UniqueRef<AST::Expression>> arguments; >- arguments.append(WTFMove(makePointerExpression)); >- auto callExpression = makeUniqueRef<AST::CallExpression>(Lexer::Token(origin), String(anderFunction->name()), WTFMove(arguments)); >- callExpression->setType(anderFunction->type().clone()); >- callExpression->setTypeAnnotation(AST::RightValue()); >- callExpression->setFunction(*anderFunction); >+ auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(Lexer::Token(origin), WTFMove(variableReference2)); >+ makePointerExpression->setType(makeUniqueRef<AST::PointerType>(Lexer::Token(origin), AST::AddressSpace::Thread, base.resolvedType().clone())); >+ makePointerExpression->setTypeAnnotation(AST::RightValue()); > >- auto dereferenceExpression = makeUniqueRef<AST::DereferenceExpression>(WTFMove(origin), WTFMove(callExpression)); >- dereferenceExpression->setType(downcast<AST::PointerType>(anderFunction->type()).elementType().clone()); >- dereferenceExpression->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); >+ Vector<UniqueRef<AST::Expression>> arguments; >+ arguments.append(WTFMove(makePointerExpression)); >+ if (additionalArgument) >+ arguments.append(WTFMove(*additionalArgument)); >+ auto callExpression = makeUniqueRef<AST::CallExpression>(Lexer::Token(origin), String(threadAnderFunction->name()), WTFMove(arguments)); >+ callExpression->setType(threadAnderFunction->type().clone()); >+ callExpression->setTypeAnnotation(AST::RightValue()); >+ callExpression->setFunction(*threadAnderFunction); > >- Vector<UniqueRef<AST::Expression>> expressions; >- expressions.append(WTFMove(assignmentExpression)); >- expressions.append(WTFMove(dereferenceExpression)); >- auto* commaExpression = AST::replaceWith<AST::CommaExpression>(dotExpression, WTFMove(origin), WTFMove(expressions)); >- commaExpression->setType(downcast<AST::PointerType>(anderFunction->type()).elementType().clone()); >- commaExpression->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); >+ auto dereferenceExpression = makeUniqueRef<AST::DereferenceExpression>(WTFMove(origin), WTFMove(callExpression)); >+ dereferenceExpression->setType(downcast<AST::PointerType>(threadAnderFunction->type()).elementType().clone()); >+ dereferenceExpression->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); > >- m_variableDeclarations.append(WTFMove(variableDeclaration)); >- return true; >- } >+ Vector<UniqueRef<AST::Expression>> expressions; >+ expressions.append(WTFMove(assignmentExpression)); >+ expressions.append(WTFMove(dereferenceExpression)); >+ auto* commaExpression = AST::replaceWith<AST::CommaExpression>(propertyAccessExpression, WTFMove(origin), WTFMove(expressions)); >+ commaExpression->setType(downcast<AST::PointerType>(threadAnderFunction->type()).elementType().clone()); >+ commaExpression->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); > >- ASSERT(dotExpression.getterFunction()); >- auto& getterFunction = *dotExpression.getterFunction(); >- Vector<UniqueRef<AST::Expression>> arguments; >- arguments.append(dotExpression.takeBase()); >- auto* callExpression = AST::replaceWith<AST::CallExpression>(dotExpression, WTFMove(origin), String(getterFunction.name()), WTFMove(arguments)); >- callExpression->setFunction(getterFunction); >- callExpression->setType(getterFunction.type().clone()); >- callExpression->setTypeAnnotation(AST::RightValue()); >+ m_variableDeclarations.append(WTFMove(variableDeclaration)); > return true; >+ > } > > class LeftValueSimplifier : public Visitor { >-public: >+private: > void visit(AST::DotExpression&) override; >+ void visit(AST::IndexExpression&) override; > void visit(AST::DereferenceExpression&) override; > >-private: >+ void finishVisiting(AST::PropertyAccessExpression&, Optional<UniqueRef<AST::Expression>>&& additionalArgument); > }; > >-void LeftValueSimplifier::visit(AST::DotExpression& dotExpression) >+void LeftValueSimplifier::finishVisiting(AST::PropertyAccessExpression& propertyAccessExpression, Optional<UniqueRef<AST::Expression>>&& additionalArgument) > { >- Visitor::visit(dotExpression); >- ASSERT(dotExpression.base().typeAnnotation().leftAddressSpace()); >- ASSERT(dotExpression.anderFunction()); >- >- Lexer::Token origin = dotExpression.origin(); >- auto* anderFunction = dotExpression.anderFunction(); >- auto& base = dotExpression.base(); >- auto leftAddressSpace = *dotExpression.base().typeAnnotation().leftAddressSpace(); >- auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(Lexer::Token(origin), dotExpression.takeBase()); >+ ASSERT(propertyAccessExpression.base().typeAnnotation().leftAddressSpace()); >+ ASSERT(propertyAccessExpression.anderFunction()); >+ >+ Lexer::Token origin = propertyAccessExpression.origin(); >+ auto* anderFunction = propertyAccessExpression.anderFunction(); >+ auto& base = propertyAccessExpression.base(); >+ auto leftAddressSpace = *propertyAccessExpression.base().typeAnnotation().leftAddressSpace(); >+ auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(Lexer::Token(origin), propertyAccessExpression.takeBase()); > makePointerExpression->setType(makeUniqueRef<AST::PointerType>(Lexer::Token(origin), leftAddressSpace, base.resolvedType().clone())); > makePointerExpression->setTypeAnnotation(AST::RightValue()); > > Vector<UniqueRef<AST::Expression>> arguments; > arguments.append(WTFMove(makePointerExpression)); >+ if (additionalArgument) >+ arguments.append(WTFMove(*additionalArgument)); > auto callExpression = makeUniqueRef<AST::CallExpression>(Lexer::Token(origin), String(anderFunction->name()), WTFMove(arguments)); > callExpression->setType(anderFunction->type().clone()); > callExpression->setTypeAnnotation(AST::RightValue()); > callExpression->setFunction(*anderFunction); > >- auto* dereferenceExpression = AST::replaceWith<AST::DereferenceExpression>(dotExpression, WTFMove(origin), WTFMove(callExpression)); >+ auto* dereferenceExpression = AST::replaceWith<AST::DereferenceExpression>(propertyAccessExpression, WTFMove(origin), 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, WTF::nullopt); >+} >+ >+void LeftValueSimplifier::visit(AST::IndexExpression& indexExpression) >+{ >+ Visitor::visit(indexExpression); >+ PropertyResolver().Visitor::visit(indexExpression.indexExpression()); >+ finishVisiting(indexExpression, indexExpression.takeIndex()); >+} >+ > 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. >- // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198170 What about function call arguments? > PropertyResolver().Visitor::visit(dereferenceExpression); > } > >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt >index 0fb5d3932d45fb0afde0959615ebd81feaa91c53..b8c63621540528f1eee58095b08961031be6862c 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt >@@ -375,6 +375,63 @@ native typedef TextureDepth2DArray<float>; > native typedef RWTextureDepth2DArray<float>; > native typedef TextureDepthCube<float>; > >+native operator uchar(ushort); >+native operator uchar(uint); >+native operator uchar(char); >+native operator uchar(short); >+native operator uchar(int); >+native operator uchar(half); >+native operator uchar(float); >+native operator ushort(uchar); >+native operator ushort(uint); >+native operator ushort(char); >+native operator ushort(short); >+native operator ushort(int); >+native operator ushort(half); >+native operator ushort(float); >+native operator uint(uchar); >+native operator uint(ushort); >+native operator uint(char); >+native operator uint(short); >+native operator uint(int); >+native operator uint(half); >+native operator uint(float); >+native operator char(uchar); >+native operator char(ushort); >+native operator char(uint); >+native operator char(short); >+native operator char(int); >+native operator char(half); >+native operator char(float); >+native operator short(uchar); >+native operator short(ushort); >+native operator short(uint); >+native operator short(char); >+native operator short(int); >+native operator short(half); >+native operator short(float); >+native operator int(uchar); >+native operator int(ushort); >+native operator int(uint); >+native operator int(char); >+native operator int(short); >+native operator int(half); >+native operator int(float); >+native operator half(uchar); >+native operator half(ushort); >+native operator half(uint); >+native operator half(char); >+native operator half(short); >+native operator half(int); >+native operator half(float); >+native operator float(uchar); >+native operator float(ushort); >+native operator float(uint); >+native operator float(char); >+native operator float(short); >+native operator float(int); >+native operator float(half); >+ > native float operator.x(float4); > native float operator.y(float4); > native float operator.z(float4); >diff --git a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLSynthesizeStructureAccessors.cpp b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLSynthesizeStructureAccessors.cpp >index 945d0ceefaa39ce5074607d2c4493cf397e983de..f89787d17804c7b4f80dc919c70da3f7a75e2b98 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLSynthesizeStructureAccessors.cpp >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLSynthesizeStructureAccessors.cpp >@@ -44,7 +44,7 @@ bool synthesizeStructureAccessors(Program& program) > bool isOperator = true; > for (auto& structureDefinition : program.structureDefinitions()) { > for (auto& structureElement : structureDefinition->structureElements()) { >- { >+ /*{ > // The getter: operator.field > auto variableDeclaration = makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(structureElement.origin()), AST::Qualifiers(), UniqueRef<AST::UnnamedType>(AST::TypeReference::wrap(Lexer::Token(structureElement.origin()), structureDefinition)), String(), WTF::nullopt, WTF::nullopt); > AST::VariableDeclarations parameters; >@@ -64,7 +64,7 @@ bool synthesizeStructureAccessors(Program& program) > AST::NativeFunctionDeclaration nativeFunctionDeclaration(AST::FunctionDeclaration(Lexer::Token(structureElement.origin()), AST::AttributeBlock(), WTF::nullopt, AST::TypeReference::wrap(Lexer::Token(structureElement.origin()), structureDefinition), makeString("operator.", structureElement.name(), '='), WTFMove(parameters), WTF::nullopt, isOperator)); > if (!program.append(WTFMove(nativeFunctionDeclaration))) > return false; >- } >+ }*/ > > // The ander: operator&.field > auto createAnder = [&](AST::AddressSpace addressSpace) -> AST::NativeFunctionDeclaration { >diff --git a/LayoutTests/webgpu/propertyresolver/ander-abstract-lvalue.html b/LayoutTests/webgpu/propertyresolver/ander-abstract-lvalue.html >new file mode 100644 >index 0000000000000000000000000000000000000000..ce14a68f14f23e8e96cc67e5706166c2f0870d5d >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/ander-abstract-lvalue.html >@@ -0,0 +1,115 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+const shaderSource = ` >+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position { >+ return position; >+} >+ >+struct Foo { >+ float x; >+} >+ >+thread float* operator&.y(thread Foo* f) { >+ return &f->x; >+} >+ >+struct Bar { >+ Foo z; >+} >+ >+Foo operator.w(Bar b) { >+ return b.z; >+} >+ >+Bar operator.w=(Bar b, Foo a) { >+ b.z = a; >+ return b; >+} >+ >+fragment float4 fragmentShader() : SV_Target 0 { >+ Bar b; >+ b.w.y = 1.0; >+ return float4(b.w.y, b.w.y, b.w.y, 1.0); >+} >+`; >+async function start() { >+ const adapter = await navigator.gpu.requestAdapter(); >+ const device = await adapter.requestDevice(); >+ >+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true}); >+ const vertexStage = {module: shaderModule, entryPoint: "vertexShader"}; >+ const fragmentStage = {module: shaderModule, entryPoint: "fragmentShader"}; >+ const primitiveTopology = "triangle-strip"; >+ const rasterizationState = {frontFace: "cw", cullMode: "none"}; >+ const alphaBlend = {}; >+ const colorBlend = {}; >+ const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL >+ const depthStencilState = null; >+ >+ const attribute0 = {shaderLocation: 0, format: "float4"}; >+ const input0 = {stride: 16, attributeSet: [attribute0]}; >+ const inputs = [input0]; >+ const vertexInput = {vertexBuffers: inputs}; >+ >+ const pipelineLayoutDescriptor = {bindGroupLayouts: []}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout}; >+ const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor); >+ >+ const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE}; >+ const vertexBuffer = device.createBuffer(vertexBufferDescriptor); >+ const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync(); >+ const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer); >+ vertexBufferFloat32Array[0] = -0.5; >+ vertexBufferFloat32Array[1] = -0.5; >+ vertexBufferFloat32Array[2] = 1.0; >+ vertexBufferFloat32Array[3] = 1; >+ vertexBufferFloat32Array[4] = -0.5; >+ vertexBufferFloat32Array[5] = 0.5; >+ vertexBufferFloat32Array[6] = 1.0; >+ vertexBufferFloat32Array[7] = 1; >+ vertexBufferFloat32Array[8] = 0.5; >+ vertexBufferFloat32Array[9] = -0.5; >+ vertexBufferFloat32Array[10] = 1.0; >+ vertexBufferFloat32Array[11] = 1; >+ vertexBufferFloat32Array[12] = 0.5; >+ vertexBufferFloat32Array[13] = 0.5; >+ vertexBufferFloat32Array[14] = 1.0; >+ vertexBufferFloat32Array[15] = 1; >+ vertexBuffer.unmap(); >+ >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("gpu"); >+ const swapChainDescriptor = {device, format: "bgra8unorm"}; >+ const swapChain = context.configureSwapChain(swapChainDescriptor); >+ const outputTexture = swapChain.getCurrentTexture(); >+ const outputTextureView = outputTexture.createDefaultView(); >+ >+ const commandEncoder = device.createCommandEncoder(); // {} >+ const red = {r: 0, g: 0, b: 1, a: 1}; >+ const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}]; >+ const depthStencilAttachment = null; >+ const renderPassDescriptor = {colorAttachments, depthStencilAttachment}; >+ const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); >+ renderPassEncoder.setPipeline(renderPipeline); >+ renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]); >+ renderPassEncoder.draw(4, 1, 0, 0); >+ renderPassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ if (window.testRunner) >+ testRunner.notifyDone(); >+} >+if (window.testRunner) >+ testRunner.waitUntilDone(); >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/propertyresolver/ander-lvalue-3-levels.html b/LayoutTests/webgpu/propertyresolver/ander-lvalue-3-levels.html >new file mode 100644 >index 0000000000000000000000000000000000000000..b3446091d0be8b605be3de3f252f365e75a9ce02 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/ander-lvalue-3-levels.html >@@ -0,0 +1,118 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+const shaderSource = ` >+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position { >+ return position; >+} >+ >+struct Foo { >+ float x; >+} >+ >+thread float* operator&.y(thread Foo* f) { >+ return &f->x; >+} >+ >+struct Bar { >+ Foo z; >+} >+ >+thread Foo* operator&.w(thread Bar* b) { >+ return &b->z; >+} >+ >+struct Baz { >+ Bar p; >+} >+ >+thread Bar* operator&.q(thread Baz* b) { >+ return &b->p; >+} >+ >+fragment float4 fragmentShader() : SV_Target 0 { >+ Baz b; >+ b.q.w.y = 1.0; >+ return float4(b.q.w.y, b.q.w.y, b.q.w.y, 1.0); >+} >+`; >+async function start() { >+ const adapter = await navigator.gpu.requestAdapter(); >+ const device = await adapter.requestDevice(); >+ >+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true}); >+ const vertexStage = {module: shaderModule, entryPoint: "vertexShader"}; >+ const fragmentStage = {module: shaderModule, entryPoint: "fragmentShader"}; >+ const primitiveTopology = "triangle-strip"; >+ const rasterizationState = {frontFace: "cw", cullMode: "none"}; >+ const alphaBlend = {}; >+ const colorBlend = {}; >+ const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL >+ const depthStencilState = null; >+ >+ const attribute0 = {shaderLocation: 0, format: "float4"}; >+ const input0 = {stride: 16, attributeSet: [attribute0]}; >+ const inputs = [input0]; >+ const vertexInput = {vertexBuffers: inputs}; >+ >+ const pipelineLayoutDescriptor = {bindGroupLayouts: []}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout}; >+ const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor); >+ >+ const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE}; >+ const vertexBuffer = device.createBuffer(vertexBufferDescriptor); >+ const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync(); >+ const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer); >+ vertexBufferFloat32Array[0] = -0.5; >+ vertexBufferFloat32Array[1] = -0.5; >+ vertexBufferFloat32Array[2] = 1.0; >+ vertexBufferFloat32Array[3] = 1; >+ vertexBufferFloat32Array[4] = -0.5; >+ vertexBufferFloat32Array[5] = 0.5; >+ vertexBufferFloat32Array[6] = 1.0; >+ vertexBufferFloat32Array[7] = 1; >+ vertexBufferFloat32Array[8] = 0.5; >+ vertexBufferFloat32Array[9] = -0.5; >+ vertexBufferFloat32Array[10] = 1.0; >+ vertexBufferFloat32Array[11] = 1; >+ vertexBufferFloat32Array[12] = 0.5; >+ vertexBufferFloat32Array[13] = 0.5; >+ vertexBufferFloat32Array[14] = 1.0; >+ vertexBufferFloat32Array[15] = 1; >+ vertexBuffer.unmap(); >+ >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("gpu"); >+ const swapChainDescriptor = {device, format: "bgra8unorm"}; >+ const swapChain = context.configureSwapChain(swapChainDescriptor); >+ const outputTexture = swapChain.getCurrentTexture(); >+ const outputTextureView = outputTexture.createDefaultView(); >+ >+ const commandEncoder = device.createCommandEncoder(); // {} >+ const red = {r: 0, g: 0, b: 1, a: 1}; >+ const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}]; >+ const depthStencilAttachment = null; >+ const renderPassDescriptor = {colorAttachments, depthStencilAttachment}; >+ const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); >+ renderPassEncoder.setPipeline(renderPipeline); >+ renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]); >+ renderPassEncoder.draw(4, 1, 0, 0); >+ renderPassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ if (window.testRunner) >+ testRunner.notifyDone(); >+} >+if (window.testRunner) >+ testRunner.waitUntilDone(); >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/propertyresolver/ander-lvalue.html b/LayoutTests/webgpu/propertyresolver/ander-lvalue.html >new file mode 100644 >index 0000000000000000000000000000000000000000..31f23f923133f934509b884e2aa2f6af0c657c81 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/ander-lvalue.html >@@ -0,0 +1,110 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+const shaderSource = ` >+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position { >+ return position; >+} >+ >+struct Foo { >+ float x; >+} >+ >+thread float* operator&.y(thread Foo* f) { >+ return &f->x; >+} >+ >+struct Bar { >+ Foo z; >+} >+ >+thread Foo* operator&.w(thread Bar* b) { >+ return &b->z; >+} >+ >+fragment float4 fragmentShader() : SV_Target 0 { >+ Bar b; >+ b.w.y = 1.0; >+ return float4(b.w.y, b.w.y, b.w.y, 1.0); >+} >+`; >+async function start() { >+ const adapter = await navigator.gpu.requestAdapter(); >+ const device = await adapter.requestDevice(); >+ >+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true}); >+ const vertexStage = {module: shaderModule, entryPoint: "vertexShader"}; >+ const fragmentStage = {module: shaderModule, entryPoint: "fragmentShader"}; >+ const primitiveTopology = "triangle-strip"; >+ const rasterizationState = {frontFace: "cw", cullMode: "none"}; >+ const alphaBlend = {}; >+ const colorBlend = {}; >+ const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL >+ const depthStencilState = null; >+ >+ const attribute0 = {shaderLocation: 0, format: "float4"}; >+ const input0 = {stride: 16, attributeSet: [attribute0]}; >+ const inputs = [input0]; >+ const vertexInput = {vertexBuffers: inputs}; >+ >+ const pipelineLayoutDescriptor = {bindGroupLayouts: []}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout}; >+ const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor); >+ >+ const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE}; >+ const vertexBuffer = device.createBuffer(vertexBufferDescriptor); >+ const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync(); >+ const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer); >+ vertexBufferFloat32Array[0] = -0.5; >+ vertexBufferFloat32Array[1] = -0.5; >+ vertexBufferFloat32Array[2] = 1.0; >+ vertexBufferFloat32Array[3] = 1; >+ vertexBufferFloat32Array[4] = -0.5; >+ vertexBufferFloat32Array[5] = 0.5; >+ vertexBufferFloat32Array[6] = 1.0; >+ vertexBufferFloat32Array[7] = 1; >+ vertexBufferFloat32Array[8] = 0.5; >+ vertexBufferFloat32Array[9] = -0.5; >+ vertexBufferFloat32Array[10] = 1.0; >+ vertexBufferFloat32Array[11] = 1; >+ vertexBufferFloat32Array[12] = 0.5; >+ vertexBufferFloat32Array[13] = 0.5; >+ vertexBufferFloat32Array[14] = 1.0; >+ vertexBufferFloat32Array[15] = 1; >+ vertexBuffer.unmap(); >+ >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("gpu"); >+ const swapChainDescriptor = {device, format: "bgra8unorm"}; >+ const swapChain = context.configureSwapChain(swapChainDescriptor); >+ const outputTexture = swapChain.getCurrentTexture(); >+ const outputTextureView = outputTexture.createDefaultView(); >+ >+ const commandEncoder = device.createCommandEncoder(); // {} >+ const red = {r: 0, g: 0, b: 1, a: 1}; >+ const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}]; >+ const depthStencilAttachment = null; >+ const renderPassDescriptor = {colorAttachments, depthStencilAttachment}; >+ const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); >+ renderPassEncoder.setPipeline(renderPipeline); >+ renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]); >+ renderPassEncoder.draw(4, 1, 0, 0); >+ renderPassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ if (window.testRunner) >+ testRunner.notifyDone(); >+} >+if (window.testRunner) >+ testRunner.waitUntilDone(); >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/propertyresolver/ander.html b/LayoutTests/webgpu/propertyresolver/ander.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f7b60e6fd13c2bc5165cc4948d3884173ec1e1ff >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/ander.html >@@ -0,0 +1,106 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+const shaderSource = ` >+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position { >+ return position; >+} >+ >+struct Foo { >+ float x; >+} >+ >+thread float* operator&.y(thread Foo* f) { >+ return &f->x; >+} >+ >+Foo generateFoo() { >+ Foo f; >+ f.x = 1.0; >+ return f; >+} >+ >+fragment float4 fragmentShader() : SV_Target 0 { >+ return float4(generateFoo().y, generateFoo().y, generateFoo().y, 1.0); >+} >+`; >+async function start() { >+ const adapter = await navigator.gpu.requestAdapter(); >+ const device = await adapter.requestDevice(); >+ >+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true}); >+ const vertexStage = {module: shaderModule, entryPoint: "vertexShader"}; >+ const fragmentStage = {module: shaderModule, entryPoint: "fragmentShader"}; >+ const primitiveTopology = "triangle-strip"; >+ const rasterizationState = {frontFace: "cw", cullMode: "none"}; >+ const alphaBlend = {}; >+ const colorBlend = {}; >+ const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL >+ const depthStencilState = null; >+ >+ const attribute0 = {shaderLocation: 0, format: "float4"}; >+ const input0 = {stride: 16, attributeSet: [attribute0]}; >+ const inputs = [input0]; >+ const vertexInput = {vertexBuffers: inputs}; >+ >+ const pipelineLayoutDescriptor = {bindGroupLayouts: []}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout}; >+ const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor); >+ >+ const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE}; >+ const vertexBuffer = device.createBuffer(vertexBufferDescriptor); >+ const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync(); >+ const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer); >+ vertexBufferFloat32Array[0] = -0.5; >+ vertexBufferFloat32Array[1] = -0.5; >+ vertexBufferFloat32Array[2] = 1.0; >+ vertexBufferFloat32Array[3] = 1; >+ vertexBufferFloat32Array[4] = -0.5; >+ vertexBufferFloat32Array[5] = 0.5; >+ vertexBufferFloat32Array[6] = 1.0; >+ vertexBufferFloat32Array[7] = 1; >+ vertexBufferFloat32Array[8] = 0.5; >+ vertexBufferFloat32Array[9] = -0.5; >+ vertexBufferFloat32Array[10] = 1.0; >+ vertexBufferFloat32Array[11] = 1; >+ vertexBufferFloat32Array[12] = 0.5; >+ vertexBufferFloat32Array[13] = 0.5; >+ vertexBufferFloat32Array[14] = 1.0; >+ vertexBufferFloat32Array[15] = 1; >+ vertexBuffer.unmap(); >+ >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("gpu"); >+ const swapChainDescriptor = {device, format: "bgra8unorm"}; >+ const swapChain = context.configureSwapChain(swapChainDescriptor); >+ const outputTexture = swapChain.getCurrentTexture(); >+ const outputTextureView = outputTexture.createDefaultView(); >+ >+ const commandEncoder = device.createCommandEncoder(); // {} >+ const red = {r: 0, g: 0, b: 1, a: 1}; >+ const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}]; >+ const depthStencilAttachment = null; >+ const renderPassDescriptor = {colorAttachments, depthStencilAttachment}; >+ const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); >+ renderPassEncoder.setPipeline(renderPipeline); >+ renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]); >+ renderPassEncoder.draw(4, 1, 0, 0); >+ renderPassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ if (window.testRunner) >+ testRunner.notifyDone(); >+} >+if (window.testRunner) >+ testRunner.waitUntilDone(); >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/propertyresolver/getter.html b/LayoutTests/webgpu/propertyresolver/getter.html >new file mode 100644 >index 0000000000000000000000000000000000000000..cc5cba018e5045afefdf51aa7d274a61ebc394f3 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/getter.html >@@ -0,0 +1,102 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+const shaderSource = ` >+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position { >+ return position; >+} >+ >+struct Foo { >+ float x; >+} >+ >+float operator.y(Foo f) { >+ return f.x; >+} >+ >+fragment float4 fragmentShader() : SV_Target 0 { >+ Foo f; >+ f.x = 1.0; >+ return float4(f.y, f.y, f.y, 1.0); >+} >+`; >+async function start() { >+ const adapter = await navigator.gpu.requestAdapter(); >+ const device = await adapter.requestDevice(); >+ >+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true}); >+ const vertexStage = {module: shaderModule, entryPoint: "vertexShader"}; >+ const fragmentStage = {module: shaderModule, entryPoint: "fragmentShader"}; >+ const primitiveTopology = "triangle-strip"; >+ const rasterizationState = {frontFace: "cw", cullMode: "none"}; >+ const alphaBlend = {}; >+ const colorBlend = {}; >+ const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL >+ const depthStencilState = null; >+ >+ const attribute0 = {shaderLocation: 0, format: "float4"}; >+ const input0 = {stride: 16, attributeSet: [attribute0]}; >+ const inputs = [input0]; >+ const vertexInput = {vertexBuffers: inputs}; >+ >+ const pipelineLayoutDescriptor = {bindGroupLayouts: []}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout}; >+ const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor); >+ >+ const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE}; >+ const vertexBuffer = device.createBuffer(vertexBufferDescriptor); >+ const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync(); >+ const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer); >+ vertexBufferFloat32Array[0] = -0.5; >+ vertexBufferFloat32Array[1] = -0.5; >+ vertexBufferFloat32Array[2] = 1.0; >+ vertexBufferFloat32Array[3] = 1; >+ vertexBufferFloat32Array[4] = -0.5; >+ vertexBufferFloat32Array[5] = 0.5; >+ vertexBufferFloat32Array[6] = 1.0; >+ vertexBufferFloat32Array[7] = 1; >+ vertexBufferFloat32Array[8] = 0.5; >+ vertexBufferFloat32Array[9] = -0.5; >+ vertexBufferFloat32Array[10] = 1.0; >+ vertexBufferFloat32Array[11] = 1; >+ vertexBufferFloat32Array[12] = 0.5; >+ vertexBufferFloat32Array[13] = 0.5; >+ vertexBufferFloat32Array[14] = 1.0; >+ vertexBufferFloat32Array[15] = 1; >+ vertexBuffer.unmap(); >+ >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("gpu"); >+ const swapChainDescriptor = {device, format: "bgra8unorm"}; >+ const swapChain = context.configureSwapChain(swapChainDescriptor); >+ const outputTexture = swapChain.getCurrentTexture(); >+ const outputTextureView = outputTexture.createDefaultView(); >+ >+ const commandEncoder = device.createCommandEncoder(); // {} >+ const red = {r: 0, g: 0, b: 1, a: 1}; >+ const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}]; >+ const depthStencilAttachment = null; >+ const renderPassDescriptor = {colorAttachments, depthStencilAttachment}; >+ const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); >+ renderPassEncoder.setPipeline(renderPipeline); >+ renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]); >+ renderPassEncoder.draw(4, 1, 0, 0); >+ renderPassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ if (window.testRunner) >+ testRunner.notifyDone(); >+} >+if (window.testRunner) >+ testRunner.waitUntilDone(); >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/propertyresolver/indexer-ander.html b/LayoutTests/webgpu/propertyresolver/indexer-ander.html >new file mode 100644 >index 0000000000000000000000000000000000000000..c66111446f4dd260cdfd8c6a88a490a2bb46cf9c >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/indexer-ander.html >@@ -0,0 +1,106 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+const shaderSource = ` >+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position { >+ return position; >+} >+ >+struct Foo { >+ float x; >+} >+ >+thread float* operator&[](thread Foo* f, uint index) { >+ return &f->x; >+} >+ >+Foo generateFoo() { >+ Foo f; >+ f.x = 1.0; >+ return f; >+} >+ >+fragment float4 fragmentShader() : SV_Target 0 { >+ return float4(generateFoo()[0], generateFoo()[1], generateFoo()[2], 1.0); >+} >+`; >+async function start() { >+ const adapter = await navigator.gpu.requestAdapter(); >+ const device = await adapter.requestDevice(); >+ >+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true}); >+ const vertexStage = {module: shaderModule, entryPoint: "vertexShader"}; >+ const fragmentStage = {module: shaderModule, entryPoint: "fragmentShader"}; >+ const primitiveTopology = "triangle-strip"; >+ const rasterizationState = {frontFace: "cw", cullMode: "none"}; >+ const alphaBlend = {}; >+ const colorBlend = {}; >+ const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL >+ const depthStencilState = null; >+ >+ const attribute0 = {shaderLocation: 0, format: "float4"}; >+ const input0 = {stride: 16, attributeSet: [attribute0]}; >+ const inputs = [input0]; >+ const vertexInput = {vertexBuffers: inputs}; >+ >+ const pipelineLayoutDescriptor = {bindGroupLayouts: []}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout}; >+ const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor); >+ >+ const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE}; >+ const vertexBuffer = device.createBuffer(vertexBufferDescriptor); >+ const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync(); >+ const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer); >+ vertexBufferFloat32Array[0] = -0.5; >+ vertexBufferFloat32Array[1] = -0.5; >+ vertexBufferFloat32Array[2] = 1.0; >+ vertexBufferFloat32Array[3] = 1; >+ vertexBufferFloat32Array[4] = -0.5; >+ vertexBufferFloat32Array[5] = 0.5; >+ vertexBufferFloat32Array[6] = 1.0; >+ vertexBufferFloat32Array[7] = 1; >+ vertexBufferFloat32Array[8] = 0.5; >+ vertexBufferFloat32Array[9] = -0.5; >+ vertexBufferFloat32Array[10] = 1.0; >+ vertexBufferFloat32Array[11] = 1; >+ vertexBufferFloat32Array[12] = 0.5; >+ vertexBufferFloat32Array[13] = 0.5; >+ vertexBufferFloat32Array[14] = 1.0; >+ vertexBufferFloat32Array[15] = 1; >+ vertexBuffer.unmap(); >+ >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("gpu"); >+ const swapChainDescriptor = {device, format: "bgra8unorm"}; >+ const swapChain = context.configureSwapChain(swapChainDescriptor); >+ const outputTexture = swapChain.getCurrentTexture(); >+ const outputTextureView = outputTexture.createDefaultView(); >+ >+ const commandEncoder = device.createCommandEncoder(); // {} >+ const red = {r: 0, g: 0, b: 1, a: 1}; >+ const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}]; >+ const depthStencilAttachment = null; >+ const renderPassDescriptor = {colorAttachments, depthStencilAttachment}; >+ const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); >+ renderPassEncoder.setPipeline(renderPipeline); >+ renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]); >+ renderPassEncoder.draw(4, 1, 0, 0); >+ renderPassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ if (window.testRunner) >+ testRunner.notifyDone(); >+} >+if (window.testRunner) >+ testRunner.waitUntilDone(); >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/propertyresolver/indexer-getter.html b/LayoutTests/webgpu/propertyresolver/indexer-getter.html >new file mode 100644 >index 0000000000000000000000000000000000000000..df16838963a2c8a69d13c4bb9978b1fdd160a871 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/indexer-getter.html >@@ -0,0 +1,101 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+const shaderSource = ` >+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position { >+ return position; >+} >+ >+struct Foo { >+ float x; >+} >+ >+float operator[](Foo f, uint index) { >+ return float(index); >+} >+ >+fragment float4 fragmentShader() : SV_Target 0 { >+ Foo f; >+ return float4(f[1], f[1], f[1], 1.0); >+} >+`; >+async function start() { >+ const adapter = await navigator.gpu.requestAdapter(); >+ const device = await adapter.requestDevice(); >+ >+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true}); >+ const vertexStage = {module: shaderModule, entryPoint: "vertexShader"}; >+ const fragmentStage = {module: shaderModule, entryPoint: "fragmentShader"}; >+ const primitiveTopology = "triangle-strip"; >+ const rasterizationState = {frontFace: "cw", cullMode: "none"}; >+ const alphaBlend = {}; >+ const colorBlend = {}; >+ const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL >+ const depthStencilState = null; >+ >+ const attribute0 = {shaderLocation: 0, format: "float4"}; >+ const input0 = {stride: 16, attributeSet: [attribute0]}; >+ const inputs = [input0]; >+ const vertexInput = {vertexBuffers: inputs}; >+ >+ const pipelineLayoutDescriptor = {bindGroupLayouts: []}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout}; >+ const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor); >+ >+ const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE}; >+ const vertexBuffer = device.createBuffer(vertexBufferDescriptor); >+ const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync(); >+ const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer); >+ vertexBufferFloat32Array[0] = -0.5; >+ vertexBufferFloat32Array[1] = -0.5; >+ vertexBufferFloat32Array[2] = 1.0; >+ vertexBufferFloat32Array[3] = 1; >+ vertexBufferFloat32Array[4] = -0.5; >+ vertexBufferFloat32Array[5] = 0.5; >+ vertexBufferFloat32Array[6] = 1.0; >+ vertexBufferFloat32Array[7] = 1; >+ vertexBufferFloat32Array[8] = 0.5; >+ vertexBufferFloat32Array[9] = -0.5; >+ vertexBufferFloat32Array[10] = 1.0; >+ vertexBufferFloat32Array[11] = 1; >+ vertexBufferFloat32Array[12] = 0.5; >+ vertexBufferFloat32Array[13] = 0.5; >+ vertexBufferFloat32Array[14] = 1.0; >+ vertexBufferFloat32Array[15] = 1; >+ vertexBuffer.unmap(); >+ >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("gpu"); >+ const swapChainDescriptor = {device, format: "bgra8unorm"}; >+ const swapChain = context.configureSwapChain(swapChainDescriptor); >+ const outputTexture = swapChain.getCurrentTexture(); >+ const outputTextureView = outputTexture.createDefaultView(); >+ >+ const commandEncoder = device.createCommandEncoder(); // {} >+ const red = {r: 0, g: 0, b: 1, a: 1}; >+ const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}]; >+ const depthStencilAttachment = null; >+ const renderPassDescriptor = {colorAttachments, depthStencilAttachment}; >+ const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); >+ renderPassEncoder.setPipeline(renderPipeline); >+ renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]); >+ renderPassEncoder.draw(4, 1, 0, 0); >+ renderPassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ if (window.testRunner) >+ testRunner.notifyDone(); >+} >+if (window.testRunner) >+ testRunner.waitUntilDone(); >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/propertyresolver/setter-abstract-lvalue.html b/LayoutTests/webgpu/propertyresolver/setter-abstract-lvalue.html >new file mode 100644 >index 0000000000000000000000000000000000000000..0ddc7b459c17fda29a1b1f758b79460008811d91 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/setter-abstract-lvalue.html >@@ -0,0 +1,120 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+const shaderSource = ` >+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position { >+ return position; >+} >+ >+struct Foo { >+ float x; >+} >+ >+float operator.y(Foo f) { >+ return f.x; >+} >+ >+Foo operator.y=(Foo f, float x) { >+ f.x = x; >+ return f; >+} >+ >+struct Bar { >+ Foo z; >+} >+ >+Foo operator.w(Bar b) { >+ return b.z; >+} >+ >+Bar operator.w=(Bar b, Foo a) { >+ b.z = a; >+ return b; >+} >+ >+fragment float4 fragmentShader() : SV_Target 0 { >+ Bar b; >+ b.w.y = 1.0; >+ return float4(b.w.y, b.w.y, b.w.y, 1.0); >+} >+`; >+async function start() { >+ const adapter = await navigator.gpu.requestAdapter(); >+ const device = await adapter.requestDevice(); >+ >+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true}); >+ const vertexStage = {module: shaderModule, entryPoint: "vertexShader"}; >+ const fragmentStage = {module: shaderModule, entryPoint: "fragmentShader"}; >+ const primitiveTopology = "triangle-strip"; >+ const rasterizationState = {frontFace: "cw", cullMode: "none"}; >+ const alphaBlend = {}; >+ const colorBlend = {}; >+ const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL >+ const depthStencilState = null; >+ >+ const attribute0 = {shaderLocation: 0, format: "float4"}; >+ const input0 = {stride: 16, attributeSet: [attribute0]}; >+ const inputs = [input0]; >+ const vertexInput = {vertexBuffers: inputs}; >+ >+ const pipelineLayoutDescriptor = {bindGroupLayouts: []}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout}; >+ const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor); >+ >+ const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE}; >+ const vertexBuffer = device.createBuffer(vertexBufferDescriptor); >+ const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync(); >+ const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer); >+ vertexBufferFloat32Array[0] = -0.5; >+ vertexBufferFloat32Array[1] = -0.5; >+ vertexBufferFloat32Array[2] = 1.0; >+ vertexBufferFloat32Array[3] = 1; >+ vertexBufferFloat32Array[4] = -0.5; >+ vertexBufferFloat32Array[5] = 0.5; >+ vertexBufferFloat32Array[6] = 1.0; >+ vertexBufferFloat32Array[7] = 1; >+ vertexBufferFloat32Array[8] = 0.5; >+ vertexBufferFloat32Array[9] = -0.5; >+ vertexBufferFloat32Array[10] = 1.0; >+ vertexBufferFloat32Array[11] = 1; >+ vertexBufferFloat32Array[12] = 0.5; >+ vertexBufferFloat32Array[13] = 0.5; >+ vertexBufferFloat32Array[14] = 1.0; >+ vertexBufferFloat32Array[15] = 1; >+ vertexBuffer.unmap(); >+ >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("gpu"); >+ const swapChainDescriptor = {device, format: "bgra8unorm"}; >+ const swapChain = context.configureSwapChain(swapChainDescriptor); >+ const outputTexture = swapChain.getCurrentTexture(); >+ const outputTextureView = outputTexture.createDefaultView(); >+ >+ const commandEncoder = device.createCommandEncoder(); // {} >+ const red = {r: 0, g: 0, b: 1, a: 1}; >+ const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}]; >+ const depthStencilAttachment = null; >+ const renderPassDescriptor = {colorAttachments, depthStencilAttachment}; >+ const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); >+ renderPassEncoder.setPipeline(renderPipeline); >+ renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]); >+ renderPassEncoder.draw(4, 1, 0, 0); >+ renderPassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ if (window.testRunner) >+ testRunner.notifyDone(); >+} >+if (window.testRunner) >+ testRunner.waitUntilDone(); >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/propertyresolver/setter-lvalue.html b/LayoutTests/webgpu/propertyresolver/setter-lvalue.html >new file mode 100644 >index 0000000000000000000000000000000000000000..9a9b4f29555bde124d99182beb3ab27da7be9c58 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/setter-lvalue.html >@@ -0,0 +1,115 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+const shaderSource = ` >+vertex float4 vertexShader(float4 position : attribute(0)) : SV_Position { >+ return position; >+} >+ >+struct Foo { >+ float x; >+} >+ >+float operator.y(Foo f) { >+ return f.x; >+} >+ >+Foo operator.y=(Foo f, float x) { >+ f.x = x; >+ return f; >+} >+ >+struct Bar { >+ Foo z; >+} >+ >+thread Foo* operator&.w(thread Bar* b) { >+ return &b->z; >+} >+ >+fragment float4 fragmentShader() : SV_Target 0 { >+ Bar b; >+ b.w.y = 1.0; >+ return float4(b.w.y, b.w.y, b.w.y, 1.0); >+} >+`; >+async function start() { >+ const adapter = await navigator.gpu.requestAdapter(); >+ const device = await adapter.requestDevice(); >+ >+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true}); >+ const vertexStage = {module: shaderModule, entryPoint: "vertexShader"}; >+ const fragmentStage = {module: shaderModule, entryPoint: "fragmentShader"}; >+ const primitiveTopology = "triangle-strip"; >+ const rasterizationState = {frontFace: "cw", cullMode: "none"}; >+ const alphaBlend = {}; >+ const colorBlend = {}; >+ const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL >+ const depthStencilState = null; >+ >+ const attribute0 = {shaderLocation: 0, format: "float4"}; >+ const input0 = {stride: 16, attributeSet: [attribute0]}; >+ const inputs = [input0]; >+ const vertexInput = {vertexBuffers: inputs}; >+ >+ const pipelineLayoutDescriptor = {bindGroupLayouts: []}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout}; >+ const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor); >+ >+ const vertexBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 4 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE}; >+ const vertexBuffer = device.createBuffer(vertexBufferDescriptor); >+ const vertexBufferArrayBuffer = await vertexBuffer.mapWriteAsync(); >+ const vertexBufferFloat32Array = new Float32Array(vertexBufferArrayBuffer); >+ vertexBufferFloat32Array[0] = -0.5; >+ vertexBufferFloat32Array[1] = -0.5; >+ vertexBufferFloat32Array[2] = 1.0; >+ vertexBufferFloat32Array[3] = 1; >+ vertexBufferFloat32Array[4] = -0.5; >+ vertexBufferFloat32Array[5] = 0.5; >+ vertexBufferFloat32Array[6] = 1.0; >+ vertexBufferFloat32Array[7] = 1; >+ vertexBufferFloat32Array[8] = 0.5; >+ vertexBufferFloat32Array[9] = -0.5; >+ vertexBufferFloat32Array[10] = 1.0; >+ vertexBufferFloat32Array[11] = 1; >+ vertexBufferFloat32Array[12] = 0.5; >+ vertexBufferFloat32Array[13] = 0.5; >+ vertexBufferFloat32Array[14] = 1.0; >+ vertexBufferFloat32Array[15] = 1; >+ vertexBuffer.unmap(); >+ >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("gpu"); >+ const swapChainDescriptor = {device, format: "bgra8unorm"}; >+ const swapChain = context.configureSwapChain(swapChainDescriptor); >+ const outputTexture = swapChain.getCurrentTexture(); >+ const outputTextureView = outputTexture.createDefaultView(); >+ >+ const commandEncoder = device.createCommandEncoder(); // {} >+ const red = {r: 0, g: 0, b: 1, a: 1}; >+ const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}]; >+ const depthStencilAttachment = null; >+ const renderPassDescriptor = {colorAttachments, depthStencilAttachment}; >+ const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); >+ renderPassEncoder.setPipeline(renderPipeline); >+ renderPassEncoder.setVertexBuffers(0, [vertexBuffer], [0]); >+ renderPassEncoder.draw(4, 1, 0, 0); >+ renderPassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ if (window.testRunner) >+ testRunner.notifyDone(); >+} >+if (window.testRunner) >+ testRunner.waitUntilDone(); >+window.addEventListener("load", start); >+</script> >+</body> >+</html>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 198399
:
371002
|
371003
|
371042
|
371101
|
371110
|
371138
|
371139
|
371857
|
371872