WebKit Bugzilla
Attachment 371139 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]
Patch
bug-198399-20190602005416.patch (text/plain), 165.12 KB, created by
Myles C. Maxfield
on 2019-06-02 00:54:17 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Myles C. Maxfield
Created:
2019-06-02 00:54:17 PDT
Size:
165.12 KB
patch
obsolete
>Subversion Revision: 246012 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 2458cfb74339378bebf54199c9dd048de52a7fdf..7d6f6ae3f8b45e7bd899da95669a472c595149f9 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,87 @@ >+2019-06-02 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!). >+ >+ This is part one of two patches which will allow buffers to work. This patch >+ adds support in the property resolver for index expressions. Index expressions >+ get turned into calls to "getter indexers", "setter indexers", or "ander >+ indexers". They work almost identically to dot expressions, except there is an >+ extra "index" expression which gets turned into an extra argument to those >+ functions. >+ >+ There's actually a bit of a trick here. Let's say we need to run a getter and >+ a setter separately (e.g. "foo[3]++;"). The index expression can't be duplicated >+ for both the getter and the setter (e.g. the functions are >+ int operator[](Foo, uint) and Foo operator[]=(Foo, uint, int), and we aren't >+ allowed to execute the index expression multiple times. Consider if that "3" >+ in the example is actually "bar()" with some side effect. So, we have to run >+ the index expression once at the correct time, and save its result to a temporary >+ variable, and then pass in the temporary variable into the getter and setter. >+ >+ So, if the code says "foo[bar()][baz()] = quux();" the following sequence of >+ functions get run: >+ >+ - bar() >+ - operator[](Foo, uint) >+ - baz() >+ - quux() >+ - operator[]=(OtherType, uint, OtherOtherType) >+ - operator[]=(Foo, uint, OtherType) >+ >+ The next patch will modify the WebGPU JavaScript implementation to send buffer >+ lengths to the shader, and for the shader compiler to correctly unpack this >+ information and place it inside the array references. That should be everything >+ that's needed to get buffers to work. After that, hooking up compute should be >+ fairly trivial. >+ >+ Tests: webgpu/propertyresolver/ander-abstract-lvalue.html >+ webgpu/propertyresolver/ander-lvalue-3-levels.html >+ webgpu/propertyresolver/ander-lvalue.html >+ webgpu/propertyresolver/ander.html >+ webgpu/propertyresolver/getter.html >+ webgpu/propertyresolver/indexer-ander-abstract-lvalue.html >+ webgpu/propertyresolver/indexer-ander-lvalue-3-levels.html >+ webgpu/propertyresolver/indexer-ander-lvalue.html >+ webgpu/propertyresolver/indexer-ander.html >+ webgpu/propertyresolver/indexer-getter.html >+ webgpu/propertyresolver/indexer-setter-abstract-lvalue-3-levels.html >+ webgpu/propertyresolver/indexer-setter-abstract-lvalue.html >+ webgpu/propertyresolver/indexer-setter-lvalue.html >+ webgpu/propertyresolver/indexer-setter.html >+ webgpu/propertyresolver/setter-abstract-lvalue-3-levels.html >+ webgpu/propertyresolver/setter-abstract-lvalue.html >+ webgpu/propertyresolver/setter-lvalue.html >+ >+ * Modules/webgpu/WHLSL/AST/WHLSLAddressSpace.h: >+ (WebCore::WHLSL::AST::toString): >+ * Modules/webgpu/WHLSL/AST/WHLSLEntryPointType.h: >+ (WebCore::WHLSL::AST::toString): >+ * Modules/webgpu/WHLSL/AST/WHLSLIndexExpression.h: >+ (WebCore::WHLSL::AST::IndexExpression::takeIndex): >+ * Modules/webgpu/WHLSL/AST/WHLSLReferenceType.h: >+ * Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp: >+ (WebCore::WHLSL::Metal::writeNativeFunction): >+ (WebCore::WHLSL::Metal::convertAddressSpace): Deleted. >+ * Modules/webgpu/WHLSL/WHLSLChecker.cpp: >+ (WebCore::WHLSL::checkOperatorOverload): >+ (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): >+ * Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt: >+ * Modules/webgpu/WHLSL/WHLSLSynthesizeStructureAccessors.cpp: >+ (WebCore::WHLSL::synthesizeStructureAccessors): >+ > 2019-05-31 Youenn Fablet <youenn@apple.com> > > Add an option to mute audio capture automatically when page is not visible >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..d9c37ce27bb8b954329d7b2a96500171390948c4 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" >@@ -354,7 +355,7 @@ static bool checkOperatorOverload(const AST::FunctionDefinition& functionDefinit > Vector<ResolvingType> argumentTypes; > Vector<std::reference_wrapper<ResolvingType>> argumentTypeReferences; > for (size_t i = 0; i < numExpectedParameters - 1; ++i) >- argumentTypes.append((*functionDefinition.parameters()[0]->type())->clone()); >+ argumentTypes.append((*functionDefinition.parameters()[i]->type())->clone()); > for (auto& argumentType : argumentTypes) > argumentTypeReferences.append(argumentType); > auto* overload = resolveFunctionOverloadImpl(*getterFuncs, argumentTypeReferences, nullptr); >@@ -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..fd55934ac71713d59ff9f8b662b0cb1bb38074c4 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&); > bool simplifyAbstractLeftValue(AST::AssignmentExpression&, AST::DotExpression&, UniqueRef<AST::Expression>&& right); > void simplifyLeftValue(AST::Expression&); > >@@ -68,6 +69,14 @@ void PropertyResolver::visit(AST::DotExpression& dotExpression) > 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)) >+ setError(); >+} >+ > void PropertyResolver::visit(AST::FunctionDefinition& functionDefinition) > { > Visitor::visit(functionDefinition); >@@ -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); >+ indexVariables.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 = [&](AST::PropertyAccessExpression& propertyAccessExpression, Optional<UniqueRef<AST::VariableDeclaration>>& indexVariable) { >+ if (!indexVariable) >+ return; >+ >+ auto& indexExpression = downcast<AST::IndexExpression>(propertyAccessExpression); >+ >+ auto variableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(*indexVariable)); >+ ASSERT(indexVariable->get().type()); >+ variableReference->setType(indexVariable->get().type()->clone()); >+ variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? >+ >+ auto assignmentExpression = makeUniqueRef<AST::AssignmentExpression>(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(propertyAccessExpression, 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(chain[0], 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; >@@ -373,6 +454,10 @@ static Optional<ModifyResult> modify(AST::DotExpression& dotExpression, std::fun > variableDeclarations.append(WTFMove(pointerVariable)); > for (auto& intermediateVariable : intermediateVariables) > variableDeclarations.append(WTFMove(intermediateVariable)); >+ for (auto& indexVariable : indexVariables) { >+ if (indexVariable) >+ variableDeclarations.append(WTFMove(*indexVariable)); >+ } > > return {{ innerLeftExpression, WTFMove(expressions), WTFMove(variableDeclarations) }}; > } >@@ -385,16 +470,13 @@ 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. >- return; >- } >+ ASSERT(is<AST::PropertyAccessExpression>(assignmentExpression.left())); > > auto type = assignmentExpression.right().resolvedType().clone(); > > 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 +506,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 +604,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 +665,150 @@ void PropertyResolver::visit(AST::ReadModifyWriteExpression& readModifyWriteExpr > m_variableDeclarations.append(WTFMove(newVariableDeclaration)); > } > >-bool PropertyResolver::simplifyRightValue(AST::DotExpression& dotExpression) >+bool PropertyResolver::simplifyRightValue(AST::PropertyAccessExpression& propertyAccessExpression) > { >- 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 (is<AST::IndexExpression>(propertyAccessExpression)) >+ arguments.append(downcast<AST::IndexExpression>(propertyAccessExpression).takeIndex()); > 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 (is<AST::IndexExpression>(propertyAccessExpression)) >+ arguments.append(downcast<AST::IndexExpression>(propertyAccessExpression).takeIndex()); >+ 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 (is<AST::IndexExpression>(propertyAccessExpression)) >+ arguments.append(downcast<AST::IndexExpression>(propertyAccessExpression).takeIndex()); >+ 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&); > }; > >-void LeftValueSimplifier::visit(AST::DotExpression& dotExpression) >+void LeftValueSimplifier::finishVisiting(AST::PropertyAccessExpression& propertyAccessExpression) > { >- 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 (is<AST::IndexExpression>(propertyAccessExpression)) >+ arguments.append(downcast<AST::IndexExpression>(propertyAccessExpression).takeIndex()); > 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); >+} >+ >+void LeftValueSimplifier::visit(AST::IndexExpression& indexExpression) >+{ >+ Visitor::visit(indexExpression); >+ PropertyResolver().Visitor::visit(indexExpression.indexExpression()); >+ finishVisiting(indexExpression); >+} >+ > void LeftValueSimplifier::visit(AST::DereferenceExpression& dereferenceExpression) > { > // Dereference expressions are the only expressions where the children might be more-right than we are. > // For example, a dereference expression may be a left value but its child may be a call expression which is a right value. > // LeftValueSimplifier doesn't handle right values, so we instead need to use PropertyResolver. >- // 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..3c0bc2b8c374bc74adaf0a45b976ed9bc01d06a8 100644 >--- a/Source/WebCore/Modules/webgpu/WHLSL/WHLSLSynthesizeStructureAccessors.cpp >+++ b/Source/WebCore/Modules/webgpu/WHLSL/WHLSLSynthesizeStructureAccessors.cpp >@@ -44,28 +44,6 @@ 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; >- parameters.append(WTFMove(variableDeclaration)); >- AST::NativeFunctionDeclaration nativeFunctionDeclaration(AST::FunctionDeclaration(Lexer::Token(structureElement.origin()), AST::AttributeBlock(), WTF::nullopt, structureElement.type().clone(), makeString("operator.", structureElement.name()), WTFMove(parameters), WTF::nullopt, isOperator)); >- if (!program.append(WTFMove(nativeFunctionDeclaration))) >- return false; >- } >- >- { >- // The setter: operator.field= >- auto variableDeclaration1 = 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); >- auto variableDeclaration2 = makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(structureElement.origin()), AST::Qualifiers(), structureElement.type().clone(), String(), WTF::nullopt, WTF::nullopt); >- AST::VariableDeclarations parameters; >- parameters.append(WTFMove(variableDeclaration1)); >- parameters.append(WTFMove(variableDeclaration2)); >- 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 { > auto argumentType = makeUniqueRef<AST::PointerType>(Lexer::Token(structureElement.origin()), addressSpace, AST::TypeReference::wrap(Lexer::Token(structureElement.origin()), structureDefinition)); >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index b258c5f1e81b1816d2352e9ec20a12d430b87628..5bd754e726b5985f3901542565cd9b0f0027a625 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,45 @@ >+2019-06-02 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!). >+ >+ * webgpu/propertyresolver/ander-abstract-lvalue-expected.html: Added. >+ * webgpu/propertyresolver/ander-abstract-lvalue.html: Added. >+ * webgpu/propertyresolver/ander-expected.html: Added. >+ * webgpu/propertyresolver/ander-lvalue-3-levels-expected.html: Added. >+ * webgpu/propertyresolver/ander-lvalue-3-levels.html: Added. >+ * webgpu/propertyresolver/ander-lvalue-expected.html: Added. >+ * webgpu/propertyresolver/ander-lvalue.html: Added. >+ * webgpu/propertyresolver/ander.html: Added. >+ * webgpu/propertyresolver/getter-expected.html: Added. >+ * webgpu/propertyresolver/getter.html: Added. >+ * webgpu/propertyresolver/indexer-ander-abstract-lvalue-expected.html: Added. >+ * webgpu/propertyresolver/indexer-ander-abstract-lvalue.html: Added. >+ * webgpu/propertyresolver/indexer-ander-expected.html: Added. >+ * webgpu/propertyresolver/indexer-ander-lvalue-3-levels-expected.html: Added. >+ * webgpu/propertyresolver/indexer-ander-lvalue-3-levels.html: Added. >+ * webgpu/propertyresolver/indexer-ander-lvalue-expected.html: Added. >+ * webgpu/propertyresolver/indexer-ander-lvalue.html: Added. >+ * webgpu/propertyresolver/indexer-ander.html: Added. >+ * webgpu/propertyresolver/indexer-getter-expected.html: Added. >+ * webgpu/propertyresolver/indexer-getter.html: Added. >+ * webgpu/propertyresolver/indexer-setter-abstract-lvalue-3-levels-expected.html: Added. >+ * webgpu/propertyresolver/indexer-setter-abstract-lvalue-3-levels.html: Added. >+ * webgpu/propertyresolver/indexer-setter-abstract-lvalue-expected.html: Added. >+ * webgpu/propertyresolver/indexer-setter-abstract-lvalue.html: Added. >+ * webgpu/propertyresolver/indexer-setter-expected.html: Added. >+ * webgpu/propertyresolver/indexer-setter-lvalue-expected.html: Added. >+ * webgpu/propertyresolver/indexer-setter-lvalue.html: Added. >+ * webgpu/propertyresolver/indexer-setter.html: Added. >+ * webgpu/propertyresolver/setter-abstract-lvalue-3-levels-expected.html: Added. >+ * webgpu/propertyresolver/setter-abstract-lvalue-3-levels.html: Added. >+ * webgpu/propertyresolver/setter-abstract-lvalue-expected.html: Added. >+ * webgpu/propertyresolver/setter-abstract-lvalue.html: Added. >+ * webgpu/propertyresolver/setter-lvalue-expected.html: Added. >+ * webgpu/propertyresolver/setter-lvalue.html: Added. >+ > 2019-05-31 Wenson Hsieh <wenson_hsieh@apple.com> > > Make tests that use UIHelper more robust under certain configurations >diff --git a/LayoutTests/webgpu/propertyresolver/ander-abstract-lvalue-expected.html b/LayoutTests/webgpu/propertyresolver/ander-abstract-lvalue-expected.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f417050f9a743f05e9006fc91ac64d502dadd633 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/ander-abstract-lvalue-expected.html >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "white"; >+ context.fillRect(100, 100, 200, 200); >+} >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >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-expected.html b/LayoutTests/webgpu/propertyresolver/ander-expected.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f417050f9a743f05e9006fc91ac64d502dadd633 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/ander-expected.html >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "white"; >+ context.fillRect(100, 100, 200, 200); >+} >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/propertyresolver/ander-lvalue-3-levels-expected.html b/LayoutTests/webgpu/propertyresolver/ander-lvalue-3-levels-expected.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f417050f9a743f05e9006fc91ac64d502dadd633 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/ander-lvalue-3-levels-expected.html >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "white"; >+ context.fillRect(100, 100, 200, 200); >+} >+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-expected.html b/LayoutTests/webgpu/propertyresolver/ander-lvalue-expected.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f417050f9a743f05e9006fc91ac64d502dadd633 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/ander-lvalue-expected.html >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "white"; >+ context.fillRect(100, 100, 200, 200); >+} >+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-expected.html b/LayoutTests/webgpu/propertyresolver/getter-expected.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f417050f9a743f05e9006fc91ac64d502dadd633 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/getter-expected.html >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "white"; >+ context.fillRect(100, 100, 200, 200); >+} >+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-abstract-lvalue-expected.html b/LayoutTests/webgpu/propertyresolver/indexer-ander-abstract-lvalue-expected.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f417050f9a743f05e9006fc91ac64d502dadd633 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/indexer-ander-abstract-lvalue-expected.html >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "white"; >+ context.fillRect(100, 100, 200, 200); >+} >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/propertyresolver/indexer-ander-abstract-lvalue.html b/LayoutTests/webgpu/propertyresolver/indexer-ander-abstract-lvalue.html >new file mode 100644 >index 0000000000000000000000000000000000000000..afce1afdfcccbb2049db3f9d055a4349817b6c6b >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/indexer-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&[](thread Foo* f, uint index) { >+ return &f->x; >+} >+ >+struct Bar { >+ Foo z; >+} >+ >+Foo operator[](Bar b, uint index) { >+ return b.z; >+} >+ >+Bar operator[]=(Bar b, uint index, Foo a) { >+ b.z = a; >+ return b; >+} >+ >+fragment float4 fragmentShader() : SV_Target 0 { >+ Bar b; >+ b[2][3] = 1.0; >+ return float4(b[2][3], b[2][3], b[2][3], 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-expected.html b/LayoutTests/webgpu/propertyresolver/indexer-ander-expected.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f417050f9a743f05e9006fc91ac64d502dadd633 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/indexer-ander-expected.html >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "white"; >+ context.fillRect(100, 100, 200, 200); >+} >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/propertyresolver/indexer-ander-lvalue-3-levels-expected.html b/LayoutTests/webgpu/propertyresolver/indexer-ander-lvalue-3-levels-expected.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f417050f9a743f05e9006fc91ac64d502dadd633 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/indexer-ander-lvalue-3-levels-expected.html >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "white"; >+ context.fillRect(100, 100, 200, 200); >+} >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/propertyresolver/indexer-ander-lvalue-3-levels.html b/LayoutTests/webgpu/propertyresolver/indexer-ander-lvalue-3-levels.html >new file mode 100644 >index 0000000000000000000000000000000000000000..c3fec6528c30a2fd36a5b05ccee90f14b122cd03 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/indexer-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&[](thread Foo* f, uint index) { >+ return &f->x; >+} >+ >+struct Bar { >+ Foo z; >+} >+ >+thread Foo* operator&[](thread Bar* b, uint index) { >+ return &b->z; >+} >+ >+struct Baz { >+ Bar p; >+} >+ >+thread Bar* operator&[](thread Baz* b, uint index) { >+ return &b->p; >+} >+ >+fragment float4 fragmentShader() : SV_Target 0 { >+ Baz b; >+ b[1][2][3] = 1.0; >+ return float4(b[1][2][3], b[1][2][3], b[1][2][3], 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-lvalue-expected.html b/LayoutTests/webgpu/propertyresolver/indexer-ander-lvalue-expected.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f417050f9a743f05e9006fc91ac64d502dadd633 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/indexer-ander-lvalue-expected.html >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "white"; >+ context.fillRect(100, 100, 200, 200); >+} >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/propertyresolver/indexer-ander-lvalue.html b/LayoutTests/webgpu/propertyresolver/indexer-ander-lvalue.html >new file mode 100644 >index 0000000000000000000000000000000000000000..354ba5ef06cf970e1ab09e03e36cfef3ac3fa595 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/indexer-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&[](thread Foo* f, uint index) { >+ return &f->x; >+} >+ >+struct Bar { >+ Foo z; >+} >+ >+thread Foo* operator&[](thread Bar* b, uint index) { >+ return &b->z; >+} >+ >+fragment float4 fragmentShader() : SV_Target 0 { >+ Bar b; >+ b[1][2] = 1.0; >+ return float4(b[1][2], b[1][2], b[1][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-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-expected.html b/LayoutTests/webgpu/propertyresolver/indexer-getter-expected.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f417050f9a743f05e9006fc91ac64d502dadd633 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/indexer-getter-expected.html >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "white"; >+ context.fillRect(100, 100, 200, 200); >+} >+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/indexer-setter-abstract-lvalue-3-levels-expected.html b/LayoutTests/webgpu/propertyresolver/indexer-setter-abstract-lvalue-3-levels-expected.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f417050f9a743f05e9006fc91ac64d502dadd633 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/indexer-setter-abstract-lvalue-3-levels-expected.html >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "white"; >+ context.fillRect(100, 100, 200, 200); >+} >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/propertyresolver/indexer-setter-abstract-lvalue-3-levels.html b/LayoutTests/webgpu/propertyresolver/indexer-setter-abstract-lvalue-3-levels.html >new file mode 100644 >index 0000000000000000000000000000000000000000..716f01db9d17439eec9beea16cf2ed2e99428862 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/indexer-setter-abstract-lvalue-3-levels.html >@@ -0,0 +1,133 @@ >+<!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 f.x; >+} >+ >+Foo operator[]=(Foo f, uint index, float x) { >+ f.x = x; >+ return f; >+} >+ >+struct Bar { >+ Foo z; >+} >+ >+Foo operator[](Bar b, uint index) { >+ return b.z; >+} >+ >+Bar operator[]=(Bar b, uint index, Foo a) { >+ b.z = a; >+ return b; >+} >+ >+struct Baz { >+ Bar p; >+} >+ >+Bar operator[](Baz b, uint index) { >+ return b.p; >+} >+ >+Baz operator[]=(Baz b, uint index, Bar a) { >+ b.p = a; >+ return b; >+} >+ >+fragment float4 fragmentShader() : SV_Target 0 { >+ Baz b; >+ b[2][3][4] = 1.0; >+ return float4(b[2][3][4], b[2][3][4], b[2][3][4], 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-setter-abstract-lvalue-expected.html b/LayoutTests/webgpu/propertyresolver/indexer-setter-abstract-lvalue-expected.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f417050f9a743f05e9006fc91ac64d502dadd633 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/indexer-setter-abstract-lvalue-expected.html >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "white"; >+ context.fillRect(100, 100, 200, 200); >+} >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/propertyresolver/indexer-setter-abstract-lvalue.html b/LayoutTests/webgpu/propertyresolver/indexer-setter-abstract-lvalue.html >new file mode 100644 >index 0000000000000000000000000000000000000000..551404fd097df06793f7a44fa7045a287325991f >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/indexer-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[](Foo f, uint index) { >+ return f.x; >+} >+ >+Foo operator[]=(Foo f, uint index, float x) { >+ f.x = x; >+ return f; >+} >+ >+struct Bar { >+ Foo z; >+} >+ >+Foo operator[](Bar b, uint index) { >+ return b.z; >+} >+ >+Bar operator[]=(Bar b, uint index, Foo a) { >+ b.z = a; >+ return b; >+} >+ >+fragment float4 fragmentShader() : SV_Target 0 { >+ Bar b; >+ b[2][3] = 1.0; >+ return float4(b[2][3], b[2][3], b[2][3], 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-setter-expected.html b/LayoutTests/webgpu/propertyresolver/indexer-setter-expected.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f417050f9a743f05e9006fc91ac64d502dadd633 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/indexer-setter-expected.html >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "white"; >+ context.fillRect(100, 100, 200, 200); >+} >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/propertyresolver/indexer-setter-lvalue-expected.html b/LayoutTests/webgpu/propertyresolver/indexer-setter-lvalue-expected.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f417050f9a743f05e9006fc91ac64d502dadd633 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/indexer-setter-lvalue-expected.html >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "white"; >+ context.fillRect(100, 100, 200, 200); >+} >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/propertyresolver/indexer-setter-lvalue.html b/LayoutTests/webgpu/propertyresolver/indexer-setter-lvalue.html >new file mode 100644 >index 0000000000000000000000000000000000000000..fd9234da78c188270e2a52ca051745da6433a212 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/indexer-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[](Foo f, uint index) { >+ return f.x; >+} >+ >+Foo operator[]=(Foo f, uint index, float x) { >+ f.x = x; >+ return f; >+} >+ >+struct Bar { >+ Foo z; >+} >+ >+thread Foo* operator&[](thread Bar* b, uint index) { >+ return &b->z; >+} >+ >+fragment float4 fragmentShader() : SV_Target 0 { >+ Bar b; >+ b[2][3] = 1.0; >+ return float4(b[2][3], b[2][3], b[2][3], 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-setter.html b/LayoutTests/webgpu/propertyresolver/indexer-setter.html >new file mode 100644 >index 0000000000000000000000000000000000000000..61da193d342ea67f966e3086c8a83a222d596000 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/indexer-setter.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&[](thread Foo* f, uint index) { >+ return &f->x; >+} >+ >+struct Bar { >+ Foo z; >+} >+ >+Foo operator[](Bar b, uint index) { >+ return b.z; >+} >+ >+Bar operator[]=(Bar b, uint index, Foo a) { >+ b.z = a; >+ return b; >+} >+ >+fragment float4 fragmentShader() : SV_Target 0 { >+ Bar b; >+ Foo foo; >+ foo.x = 1.0; >+ b[1] = foo; >+ foo = b[1]; >+ return float4(foo.x, foo.x, foo.x, 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-3-levels-expected.html b/LayoutTests/webgpu/propertyresolver/setter-abstract-lvalue-3-levels-expected.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f417050f9a743f05e9006fc91ac64d502dadd633 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/setter-abstract-lvalue-3-levels-expected.html >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "white"; >+ context.fillRect(100, 100, 200, 200); >+} >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >diff --git a/LayoutTests/webgpu/propertyresolver/setter-abstract-lvalue-3-levels.html b/LayoutTests/webgpu/propertyresolver/setter-abstract-lvalue-3-levels.html >new file mode 100644 >index 0000000000000000000000000000000000000000..6e912f516d7bdf672112b356f24b427814268659 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/setter-abstract-lvalue-3-levels.html >@@ -0,0 +1,133 @@ >+<!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; >+} >+ >+struct Baz { >+ Bar p; >+} >+ >+Bar operator.q(Baz b) { >+ return b.p; >+} >+ >+Baz operator.q=(Baz b, Bar a) { >+ b.p = a; >+ return b; >+} >+ >+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/setter-abstract-lvalue-expected.html b/LayoutTests/webgpu/propertyresolver/setter-abstract-lvalue-expected.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f417050f9a743f05e9006fc91ac64d502dadd633 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/setter-abstract-lvalue-expected.html >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "white"; >+ context.fillRect(100, 100, 200, 200); >+} >+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-expected.html b/LayoutTests/webgpu/propertyresolver/setter-lvalue-expected.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f417050f9a743f05e9006fc91ac64d502dadd633 >--- /dev/null >+++ b/LayoutTests/webgpu/propertyresolver/setter-lvalue-expected.html >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "white"; >+ context.fillRect(100, 100, 200, 200); >+} >+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
Flags:
saam
:
review+
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 198399
:
371002
|
371003
|
371042
|
371101
|
371110
|
371138
| 371139 |
371857
|
371872