WebKit Bugzilla
Attachment 372083 Details for
Bug 198580
: [WHLSL] Do not generate duplicate constructors/copy constructors in synthesizeConstructors
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
WIP
c-backup.diff (text/plain), 70.33 KB, created by
Saam Barati
on 2019-06-13 16:52:55 PDT
(
hide
)
Description:
WIP
Filename:
MIME Type:
Creator:
Saam Barati
Created:
2019-06-13 16:52:55 PDT
Size:
70.33 KB
patch
obsolete
>Index: Source/WebCore/ChangeLog >=================================================================== >--- Source/WebCore/ChangeLog (revision 246409) >+++ Source/WebCore/ChangeLog (working copy) >@@ -1,3 +1,76 @@ >+2019-06-13 Saam Barati <sbarati@apple.com> >+ >+ [WHLSL] Implement out-of-bounds and nullptr behavior >+ https://bugs.webkit.org/show_bug.cgi?id=198600 >+ <rdar://problem/51668853> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ The behavior we're implementing is: >+ - OOB writes are ignored. >+ - OOB reads return zero. >+ - Writes to null are ignored. >+ - Reads from null return zero. >+ - &*x == x, including &*null == null. >+ >+ We implement this like so: >+ - The value stack in FunctionWriter turns into a stack of pairs: rvalues and lvalues. >+ rvalues are represented the same as before. Lvalues are always pointers. >+ - Anything that produces an lvalue must push a pointer to the stack. Not >+ all things produce lvalues, so that entry in the stack may be empty. >+ However, all things that produce lvalues also produce rvalues. So, "*x = 42" works, >+ and so does "foo(*x)". Nodes that produce lvalues are responsible for also producing >+ an rvalue, which should be the value as if the lvalue was dereferenced at that point >+ in program execution. So the "*x" in "thread int* x = null; *x" produces the int zero >+ for its rvalue, and null for its lvalue. >+ - Dereference just works, as dereference produces both an lvalue and rvalue. Dereference >+ node's child must also be an lvalue. So we just forward that value along on >+ the stack. For the rvalue, if we try to dereference nullptr, we just fill in >+ zero bytes instead. Otherwise, the rvalue is the result of dereferencing the >+ non-null pointer. >+ - Assignment expressions check if the incoming lvalue is null. If it is, it >+ skips the assignment. >+ - operator&[] returns nullptr on an OOB access. Then, based on the above >+ behavior, we get the desired OOB reads return zero, and OOB writes are >+ ignored. >+ - MakePointerExpression just takes the last lvalue off the stack (which must >+ be a pointer) and returns it as an rvalue. >+ - VariableReference will push both the variable value and a pointer to the variable >+ onto the stack. >+ >+ This patch also fixes a few bugs where we weren't giving certain AST nodes the >+ proper address space values. >+ >+ This patch also removes code to generate native functions for operators >+ "operator[]" and "operator[]=" as we should never be generating these >+ ourselves. We should only be generating the "operator&[]" ander. >+ >+ Tests: webgpu/whlsl-null-dereference.html >+ webgpu/whlsl-oob-access.html >+ >+ * Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp: >+ (WebCore::WHLSL::Metal::FunctionDefinitionWriter::FunctionDefinitionWriter): >+ (WebCore::WHLSL::Metal::FunctionDefinitionWriter::appendRightValue): >+ (WebCore::WHLSL::Metal::FunctionDefinitionWriter::appendLeftValue): >+ (WebCore::WHLSL::Metal::FunctionDefinitionWriter::takeLastValue): >+ (WebCore::WHLSL::Metal::FunctionDefinitionWriter::takeLastLeftValue): >+ (WebCore::WHLSL::Metal::FunctionDefinitionWriter::visit): >+ (WebCore::WHLSL::Metal::FunctionDefinitionWriter::emitLoop): >+ * Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp: >+ (WebCore::WHLSL::Metal::writeNativeFunction): >+ * Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.h: >+ * Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp: >+ (WebCore::WHLSL::Metal::TypeNamer::emitUnnamedTypeDefinition): >+ * Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp: >+ (WebCore::WHLSL::PreserveLifetimes::assignVariableIntoStruct): >+ * Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp: >+ (WebCore::WHLSL::PropertyResolver::visit): >+ * Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt: >+ * platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm: >+ (WebCore::trySetFunctions): >+ * platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm: >+ (WebCore::trySetFunctions): >+ > 2019-06-13 Commit Queue <commit-queue@webkit.org> > > Unreviewed, rolling out r246396 and r246397. >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLInferTypes.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLInferTypes.cpp (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLInferTypes.cpp (working copy) >@@ -61,6 +61,8 @@ static bool matches(const AST::Type& uni > auto& unnamedThis = downcast<AST::UnnamedType>(unifyThis); > auto& unnamedOther = downcast<AST::UnnamedType>(unifyOther); > ASSERT(!is<AST::TypeReference>(unnamedThis) && !is<AST::TypeReference>(unnamedOther)); >+ return unnamedThis == unnamedOther; >+ /* > if (is<AST::PointerType>(unnamedThis) && is<AST::PointerType>(unnamedOther)) { > auto& pointerThis = downcast<AST::PointerType>(unnamedThis); > auto& pointerOther = downcast<AST::PointerType>(unnamedOther); >@@ -83,6 +85,7 @@ static bool matches(const AST::Type& uni > return matches(arrayThis.type(), arrayOther.type()); > } > return false; >+ */ > } > return false; > } >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLNameResolver.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLNameResolver.cpp (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLNameResolver.cpp (working copy) >@@ -88,6 +88,7 @@ void NameResolver::visit(AST::FunctionDe > NameContext newNameContext(&m_nameContext); > NameResolver newNameResolver(newNameContext); > newNameResolver.setCurrentFunctionDefinition(m_currentFunction); >+ newNameResolver.setIsResolvingCalls(m_isResolvingCalls); > checkErrorAndVisit(functionDefinition.type()); > for (auto& parameter : functionDefinition.parameters()) > newNameResolver.checkErrorAndVisit(parameter); >@@ -99,6 +100,7 @@ void NameResolver::visit(AST::Block& blo > NameContext nameContext(&m_nameContext); > NameResolver newNameResolver(nameContext); > newNameResolver.setCurrentFunctionDefinition(m_currentFunction); >+ newNameResolver.setIsResolvingCalls(m_isResolvingCalls); > newNameResolver.Visitor::visit(block); > } > >@@ -108,11 +110,13 @@ void NameResolver::visit(AST::IfStatemen > NameContext nameContext(&m_nameContext); > NameResolver newNameResolver(nameContext); > newNameResolver.setCurrentFunctionDefinition(m_currentFunction); >+ newNameResolver.setIsResolvingCalls(m_isResolvingCalls); > newNameResolver.checkErrorAndVisit(ifStatement.body()); > if (ifStatement.elseBody()) { > NameContext nameContext(&m_nameContext); > NameResolver newNameResolver(nameContext); > newNameResolver.setCurrentFunctionDefinition(m_currentFunction); >+ newNameResolver.setIsResolvingCalls(m_isResolvingCalls); > newNameResolver.checkErrorAndVisit(*ifStatement.elseBody()); > } > } >@@ -123,6 +127,7 @@ void NameResolver::visit(AST::WhileLoop& > NameContext nameContext(&m_nameContext); > NameResolver newNameResolver(nameContext); > newNameResolver.setCurrentFunctionDefinition(m_currentFunction); >+ newNameResolver.setIsResolvingCalls(m_isResolvingCalls); > newNameResolver.checkErrorAndVisit(whileLoop.body()); > } > >@@ -131,6 +136,7 @@ void NameResolver::visit(AST::DoWhileLoo > NameContext nameContext(&m_nameContext); > NameResolver newNameResolver(nameContext); > newNameResolver.setCurrentFunctionDefinition(m_currentFunction); >+ newNameResolver.setIsResolvingCalls(m_isResolvingCalls); > newNameResolver.checkErrorAndVisit(whileLoop.body()); > checkErrorAndVisit(whileLoop.conditional()); > } >@@ -140,6 +146,7 @@ void NameResolver::visit(AST::ForLoop& f > NameContext nameContext(&m_nameContext); > NameResolver newNameResolver(nameContext); > newNameResolver.setCurrentFunctionDefinition(m_currentFunction); >+ newNameResolver.setIsResolvingCalls(m_isResolvingCalls); > newNameResolver.Visitor::visit(forLoop); > } > >@@ -174,12 +181,14 @@ void NameResolver::visit(AST::Return& re > > void NameResolver::visit(AST::PropertyAccessExpression& propertyAccessExpression) > { >- if (auto* getterFunctions = m_nameContext.getFunctions(propertyAccessExpression.getterFunctionName())) >- propertyAccessExpression.setPossibleGetterOverloads(*getterFunctions); >- if (auto* setterFunctions = m_nameContext.getFunctions(propertyAccessExpression.setterFunctionName())) >- propertyAccessExpression.setPossibleSetterOverloads(*setterFunctions); >- if (auto* anderFunctions = m_nameContext.getFunctions(propertyAccessExpression.anderFunctionName())) >- propertyAccessExpression.setPossibleAnderOverloads(*anderFunctions); >+ if (m_isResolvingCalls) { >+ if (auto* getterFunctions = m_nameContext.getFunctions(propertyAccessExpression.getterFunctionName())) >+ propertyAccessExpression.setPossibleGetterOverloads(*getterFunctions); >+ if (auto* setterFunctions = m_nameContext.getFunctions(propertyAccessExpression.setterFunctionName())) >+ propertyAccessExpression.setPossibleSetterOverloads(*setterFunctions); >+ if (auto* anderFunctions = m_nameContext.getFunctions(propertyAccessExpression.anderFunctionName())) >+ propertyAccessExpression.setPossibleAnderOverloads(*anderFunctions); >+ } > Visitor::visit(propertyAccessExpression); > } > >@@ -210,23 +219,25 @@ void NameResolver::visit(AST::DotExpress > > void NameResolver::visit(AST::CallExpression& callExpression) > { >- if (!callExpression.hasOverloads()) { >- if (auto* functions = m_nameContext.getFunctions(callExpression.name())) >- callExpression.setOverloads(*functions); >- else { >- if (auto* types = m_nameContext.getTypes(callExpression.name())) { >- if (types->size() == 1) { >- if (auto* functions = m_nameContext.getFunctions("operator cast"_str)) { >- callExpression.setCastData((*types)[0].get()); >- callExpression.setOverloads(*functions); >+ if (m_isResolvingCalls) { >+ if (!callExpression.hasOverloads()) { >+ if (auto* functions = m_nameContext.getFunctions(callExpression.name())) >+ callExpression.setOverloads(*functions); >+ else { >+ if (auto* types = m_nameContext.getTypes(callExpression.name())) { >+ if (types->size() == 1) { >+ if (auto* functions = m_nameContext.getFunctions("operator cast"_str)) { >+ callExpression.setCastData((*types)[0].get()); >+ callExpression.setOverloads(*functions); >+ } > } > } > } > } >- } >- if (!callExpression.hasOverloads()) { >- setError(); >- return; >+ if (!callExpression.hasOverloads()) { >+ setError(); >+ return; >+ } > } > Visitor::visit(callExpression); > } >@@ -295,6 +306,20 @@ bool resolveNamesInFunctions(Program& pr > return true; > } > >+bool resolveCallsInFunctions(Program& program, NameResolver& nameResolver) >+{ >+ nameResolver.setIsResolvingCalls(true); >+ for (auto& functionDefinition : program.functionDefinitions()) { >+ nameResolver.setCurrentFunctionDefinition(&functionDefinition); >+ nameResolver.checkErrorAndVisit(functionDefinition); >+ if (nameResolver.error()) >+ return false; >+ } >+ nameResolver.setCurrentFunctionDefinition(nullptr); >+ nameResolver.setIsResolvingCalls(false); >+ return true; >+} >+ > } // namespace WHLSL > > } // namespace WebCore >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLNameResolver.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLNameResolver.h (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLNameResolver.h (working copy) >@@ -50,6 +50,8 @@ public: > m_currentFunction = functionDefinition; > } > >+ void setIsResolvingCalls(bool isResolvingCalls) { m_isResolvingCalls = isResolvingCalls; } >+ > private: > void visit(AST::TypeReference&) override; > void visit(AST::Block&) override; >@@ -68,10 +70,12 @@ private: > NameContext& m_nameContext; > HashSet<AST::TypeReference*> m_typeReferences; > AST::FunctionDefinition* m_currentFunction { nullptr }; >+ bool m_isResolvingCalls { false }; > }; > > bool resolveNamesInTypes(Program&, NameResolver&); > bool resolveNamesInFunctions(Program&, NameResolver&); >+bool resolveCallsInFunctions(Program&, NameResolver&); > > } // namespace WHLSL > >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp (working copy) >@@ -125,8 +125,9 @@ static Optional<Program> prepareShared(S > RUN_PASS(synthesizeStructureAccessors, program); > RUN_PASS(synthesizeEnumerationFunctions, program); > RUN_PASS(synthesizeArrayOperatorLength, program); >- RUN_PASS(synthesizeConstructors, program); > RUN_PASS(resolveNamesInFunctions, program, nameResolver); >+ RUN_PASS(synthesizeConstructors, program); >+ RUN_PASS(resolveCallsInFunctions, program, nameResolver); > RUN_PASS(checkDuplicateFunctions, program); > > RUN_PASS(check, program); >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp (working copy) >@@ -110,7 +110,7 @@ public: > > auto rhs = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(variable)); > rhs->setType(variable.type()->clone()); >- rhs->setTypeAnnotation(AST::RightValue()); >+ rhs->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); > > auto assignment = makeUniqueRef<AST::AssignmentExpression>(variable.origin(), WTFMove(lhs), WTFMove(rhs)); > assignment->setType(variable.type()->clone()); >@@ -136,7 +136,7 @@ public: > > auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(functionDefinition.origin(), WTFMove(structVariableReference)); > makePointerExpression->setType(m_pointerToStructType->clone()); >- makePointerExpression->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); >+ makePointerExpression->setTypeAnnotation(AST::RightValue()); > > auto pointerDeclaration = makeUniqueRef<AST::VariableDeclaration>(functionDefinition.origin(), AST::Qualifiers(), > m_pointerToStructType->clone(), "wrapper"_s, WTF::nullopt, Optional<UniqueRef<AST::Expression>>(WTFMove(makePointerExpression))); >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp (working copy) >@@ -687,7 +687,11 @@ void PropertyResolver::visit(AST::ReadMo > expressions.append(WTFMove(assignmentExpression)); > } > >- return {{ WTFMove(expressions), readModifyWriteExpression.newVariableReference() }}; >+ auto variableReference = readModifyWriteExpression.newVariableReference(); >+ variableReference->setType(readModifyWriteExpression.leftValue().resolvedType().clone()); >+ variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? >+ >+ return {{ WTFMove(expressions), WTFMove(variableReference) }}; > }); > > if (!modifyResult) { >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt (working copy) >@@ -439,6 +439,9 @@ native uint operator+(uint, uint); > native bool operator<(int, int); > native bool operator<(uint, uint); > native bool operator<(float, float); >+native bool operator==(float, float); >+native bool operator==(int, int); >+native bool operator==(thread int*, thread int*); > native float operator*(float, float); > > native bool operator.x(bool2); >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLSynthesizeConstructors.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLSynthesizeConstructors.cpp (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLSynthesizeConstructors.cpp (working copy) >@@ -41,51 +41,105 @@ > #include "WHLSLVariableDeclaration.h" > #include "WHLSLVisitor.h" > >+#include <wtf/DataLog.h> >+#include "WHLSLASTDumper.h" >+ > namespace WebCore { > > namespace WHLSL { > >+class UnnamedTypeKey { >+public: >+ UnnamedTypeKey() = default; >+ UnnamedTypeKey(WTF::HashTableDeletedValueType) >+ { >+ m_type = bitwise_cast<AST::UnnamedType*>(static_cast<uintptr_t>(1)); >+ } >+ >+ UnnamedTypeKey(const AST::UnnamedType& type) >+ : m_type(&type) >+ { } >+ >+ bool isEmptyValue() const { return !m_type; } >+ bool isHashTableDeletedValue() const { return m_type == bitwise_cast<AST::UnnamedType*>(static_cast<uintptr_t>(1)); } >+ >+ unsigned hash() const >+ { >+ return m_type->hash(); >+ } >+ >+ bool operator==(const UnnamedTypeKey& other) const >+ { >+ return *m_type == *other.m_type; >+ } >+ >+ AST::UnnamedType& unnamedType() const { return const_cast<AST::UnnamedType&>(*m_type); } >+ >+ struct Hash { >+ static unsigned hash(const UnnamedTypeKey& key) >+ { >+ return key.hash(); >+ } >+ >+ static bool equal(const UnnamedTypeKey& a, const UnnamedTypeKey& b) >+ { >+ return a == b; >+ } >+ >+ static const bool safeToCompareToEmptyOrDeleted = false; >+ static const bool emptyValueIsZero = true; >+ }; >+ >+ struct Traits : public WTF::SimpleClassHashTraits<UnnamedTypeKey> { >+ static const bool hasIsEmptyValueFunction = true; >+ static bool isEmptyValue(const UnnamedTypeKey& key) { return key.isEmptyValue(); } >+ }; >+ >+private: >+ const AST::UnnamedType* m_type { nullptr }; >+}; >+ > class FindAllTypes : public Visitor { > public: > ~FindAllTypes() = default; > > void visit(AST::PointerType& pointerType) override > { >- m_unnamedTypes.append(pointerType); >+ m_unnamedTypes.add(UnnamedTypeKey { pointerType }); > Visitor::visit(pointerType); > } > > void visit(AST::ArrayReferenceType& arrayReferenceType) override > { >- m_unnamedTypes.append(arrayReferenceType); >+ m_unnamedTypes.add(UnnamedTypeKey { arrayReferenceType }); > Visitor::visit(arrayReferenceType); > } > > void visit(AST::ArrayType& arrayType) override > { >- m_unnamedTypes.append(arrayType); >+ m_unnamedTypes.add(UnnamedTypeKey { arrayType }); > Visitor::visit(arrayType); > } > > void visit(AST::EnumerationDefinition& enumerationDefinition) override > { >- m_namedTypes.append(enumerationDefinition); >+ appendNamedType(enumerationDefinition); > Visitor::visit(enumerationDefinition); > } > > void visit(AST::StructureDefinition& structureDefinition) override > { >- m_namedTypes.append(structureDefinition); >+ appendNamedType(structureDefinition); > Visitor::visit(structureDefinition); > } > > void visit(AST::NativeTypeDeclaration& nativeTypeDeclaration) override > { >- m_namedTypes.append(nativeTypeDeclaration); >+ appendNamedType(nativeTypeDeclaration); > Visitor::visit(nativeTypeDeclaration); > } > >- Vector<std::reference_wrapper<AST::UnnamedType>> takeUnnamedTypes() >+ HashSet<UnnamedTypeKey, UnnamedTypeKey::Hash, UnnamedTypeKey::Traits> takeUnnamedTypes() > { > return WTFMove(m_unnamedTypes); > } >@@ -96,7 +150,16 @@ public: > } > > private: >- Vector<std::reference_wrapper<AST::UnnamedType>> m_unnamedTypes; >+ void appendNamedType(AST::NamedType& type) >+ { >+//#if !ASSERT_DISABLED >+ for (auto& entry : m_namedTypes) >+ RELEASE_ASSERT(&entry.get().unifyNode() != &type.unifyNode()); >+//#endif >+ m_namedTypes.append(type); >+ } >+ >+ HashSet<UnnamedTypeKey, UnnamedTypeKey::Hash, UnnamedTypeKey::Traits> m_unnamedTypes; > Vector<std::reference_wrapper<AST::NamedType>> m_namedTypes; > }; > >@@ -109,14 +172,15 @@ bool synthesizeConstructors(Program& pro > > bool isOperator = true; > >- for (auto& unnamedType : unnamedTypes) { >- auto variableDeclaration = makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(unnamedType.get().origin()), AST::Qualifiers(), unnamedType.get().clone(), String(), WTF::nullopt, WTF::nullopt); >+ for (auto& unnamedTypeKey : unnamedTypes) { >+ auto& unnamedType = unnamedTypeKey.unnamedType(); >+ auto variableDeclaration = makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(unnamedType.origin()), AST::Qualifiers(), unnamedType.clone(), String(), WTF::nullopt, WTF::nullopt); > AST::VariableDeclarations parameters; > parameters.append(WTFMove(variableDeclaration)); >- AST::NativeFunctionDeclaration copyConstructor(AST::FunctionDeclaration(Lexer::Token(unnamedType.get().origin()), AST::AttributeBlock(), WTF::nullopt, unnamedType.get().clone(), "operator cast"_str, WTFMove(parameters), WTF::nullopt, isOperator)); >+ AST::NativeFunctionDeclaration copyConstructor(AST::FunctionDeclaration(Lexer::Token(unnamedType.origin()), AST::AttributeBlock(), WTF::nullopt, unnamedType.clone(), "operator cast"_str, WTFMove(parameters), WTF::nullopt, isOperator)); > program.append(WTFMove(copyConstructor)); > >- AST::NativeFunctionDeclaration defaultConstructor(AST::FunctionDeclaration(Lexer::Token(unnamedType.get().origin()), AST::AttributeBlock(), WTF::nullopt, unnamedType.get().clone(), "operator cast"_str, AST::VariableDeclarations(), WTF::nullopt, isOperator)); >+ AST::NativeFunctionDeclaration defaultConstructor(AST::FunctionDeclaration(Lexer::Token(unnamedType.origin()), AST::AttributeBlock(), WTF::nullopt, unnamedType.clone(), "operator cast"_str, AST::VariableDeclarations(), WTF::nullopt, isOperator)); > if (!program.append(WTFMove(defaultConstructor))) > return false; > } >Index: Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLArrayReferenceType.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLArrayReferenceType.h (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLArrayReferenceType.h (working copy) >@@ -63,6 +63,15 @@ public: > return this->Base::hash() ^ StringHasher::computeLiteralHash("array"); > } > >+ bool operator==(const UnnamedType& other) const override >+ { >+ if (!is<ArrayReferenceType>(other)) >+ return false; >+ >+ return addressSpace() == downcast<ArrayReferenceType>(other).addressSpace() >+ && elementType() == downcast<ArrayReferenceType>(other).elementType(); >+ } >+ > private: > }; > >Index: Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLArrayType.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLArrayType.h (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLArrayType.h (working copy) >@@ -69,6 +69,15 @@ public: > return WTF::IntHash<unsigned>::hash(m_numElements) ^ m_elementType->hash(); > } > >+ bool operator==(const UnnamedType& other) const override >+ { >+ if (!is<ArrayType>(other)) >+ return false; >+ >+ return numElements() == downcast<ArrayType>(other).numElements() >+ && type() == downcast<ArrayType>(other).type(); >+ } >+ > private: > UniqueRef<UnnamedType> m_elementType; > unsigned m_numElements; >Index: Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLPointerType.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLPointerType.h (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLPointerType.h (working copy) >@@ -63,6 +63,15 @@ public: > return this->Base::hash() ^ StringHasher::computeLiteralHash("pointer"); > } > >+ bool operator==(const UnnamedType& other) const override >+ { >+ if (!is<PointerType>(other)) >+ return false; >+ >+ return addressSpace() == downcast<PointerType>(other).addressSpace() >+ && elementType() == downcast<PointerType>(other).elementType(); >+ } >+ > private: > }; > >Index: Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLTypeReference.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLTypeReference.h (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLTypeReference.h (working copy) >@@ -34,6 +34,8 @@ > #include <wtf/UniqueRef.h> > #include <wtf/text/WTFString.h> > >+#include <wtf/DataLog.h> >+ > namespace WebCore { > > namespace WHLSL { >@@ -104,9 +106,20 @@ public: > // Currently, we only use this function after the name resolver runs. > // Relying on having a resolved type simplifies this implementation. > ASSERT(m_resolvedType); >+ //dataLogLn(m_name); >+ //dataLogLn("this = ", RawPointer(this)); > return WTF::PtrHash<const Type*>::hash(&unifyNode()); > } > >+ bool operator==(const UnnamedType& other) const override >+ { >+ ASSERT(m_resolvedType); >+ if (!is<TypeReference>(other)) >+ return false; >+ >+ return &unifyNode() == &downcast<TypeReference>(other).unifyNode(); >+ } >+ > private: > String m_name; > TypeArguments m_typeArguments; >Index: Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLUnnamedType.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLUnnamedType.h (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLUnnamedType.h (working copy) >@@ -64,6 +64,7 @@ public: > virtual UniqueRef<UnnamedType> clone() const = 0; > > virtual unsigned hash() const = 0; >+ virtual bool operator==(const UnnamedType&) const = 0; > > const Lexer::Token& origin() const { return m_origin; } > >Index: Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp (working copy) >@@ -88,8 +88,18 @@ public: > , m_functionMapping(functionMapping) > , m_layout(layout) > { >+ m_stringBuilder.append(makeString( >+ "template <typename T>\n" >+ "inline void ", memsetZeroFunctionName, "(thread T& value)\n" >+ "{\n" >+ " thread char* ptr = static_cast<thread char*>(static_cast<thread void*>(&value));\n" >+ " for (size_t i = 0; i < sizeof(T); ++i)\n" >+ " ptr[i] = 0;\n" >+ "}\n")); > } > >+ static constexpr const char* memsetZeroFunctionName = "memsetZero"; >+ > virtual ~FunctionDefinitionWriter() = default; > > String toString() { return m_stringBuilder.toString(); } >@@ -153,12 +163,41 @@ protected: > return makeString("variable", m_variableCount++); > } > >+ struct StackItem { >+ String value; >+ String leftValue; >+ }; >+ >+ void appendRightValue(AST::Expression&, String value) >+ { >+ m_stack.append({ WTFMove(value), String() }); >+ } >+ >+ void appendLeftValue(AST::Expression& expression, String value, String leftValue) >+ { >+ ASSERT_UNUSED(expression, expression.typeAnnotation().leftAddressSpace()); >+ m_stack.append({ WTFMove(value), WTFMove(leftValue) }); >+ } >+ >+ String takeLastValue() >+ { >+ ASSERT(m_stack.last().value); >+ return m_stack.takeLast().value; >+ } >+ >+ String takeLastLeftValue() >+ { >+ ASSERT(m_stack.last().leftValue); >+ return m_stack.takeLast().leftValue; >+ } >+ > Intrinsics& m_intrinsics; > TypeNamer& m_typeNamer; > HashMap<AST::FunctionDeclaration*, String>& m_functionMapping; > HashMap<AST::VariableDeclaration*, String> m_variableMapping; > StringBuilder m_stringBuilder; >- Vector<String> m_stack; >+ >+ Vector<StackItem> m_stack; > std::unique_ptr<EntryPointScaffolding> m_entryPointScaffolding; > Layout& m_layout; > unsigned m_variableCount { 0 }; >@@ -169,7 +208,7 @@ void FunctionDefinitionWriter::visit(AST > { > auto iterator = m_functionMapping.find(&nativeFunctionDeclaration); > ASSERT(iterator != m_functionMapping.end()); >- m_stringBuilder.append(writeNativeFunction(nativeFunctionDeclaration, iterator->value, m_intrinsics, m_typeNamer)); >+ m_stringBuilder.append(writeNativeFunction(nativeFunctionDeclaration, iterator->value, m_intrinsics, m_typeNamer, memsetZeroFunctionName)); > } > > void FunctionDefinitionWriter::visit(AST::FunctionDefinition& functionDefinition) >@@ -246,7 +285,7 @@ void FunctionDefinitionWriter::visit(AST > void FunctionDefinitionWriter::visit(AST::EffectfulExpressionStatement& effectfulExpressionStatement) > { > checkErrorAndVisit(effectfulExpressionStatement.effectfulExpression()); >- m_stack.takeLast(); // The statement is already effectful, so we don't need to do anything with the result. >+ takeLastValue(); // The statement is already effectful, so we don't need to do anything with the result. > } > > void FunctionDefinitionWriter::visit(AST::Fallthrough&) >@@ -264,7 +303,7 @@ void FunctionDefinitionWriter::emitLoop( > > if (loopConditionLocation == LoopConditionLocation::BeforeBody && conditionExpression) { > checkErrorAndVisit(*conditionExpression); >- m_stringBuilder.append(makeString("if (!", m_stack.takeLast(), ") break;\n")); >+ m_stringBuilder.append(makeString("if (!", takeLastValue(), ") break;\n")); > } > > m_stringBuilder.append("do {\n"); >@@ -276,12 +315,12 @@ void FunctionDefinitionWriter::emitLoop( > checkErrorAndVisit(*increment); > // Expression results get pushed to m_stack. We don't use the result > // of increment, so we dispense of that now. >- m_stack.takeLast(); >+ takeLastValue(); > } > > if (loopConditionLocation == LoopConditionLocation::AfterBody && conditionExpression) { > checkErrorAndVisit(*conditionExpression); >- m_stringBuilder.append(makeString("if (!", m_stack.takeLast(), ") break;\n")); >+ m_stringBuilder.append(makeString("if (!", takeLastValue(), ") break;\n")); > } > > m_stringBuilder.append("} \n"); >@@ -305,7 +344,7 @@ void FunctionDefinitionWriter::visit(AST > checkErrorAndVisit(statement); > }, [&](UniqueRef<AST::Expression>& expression) { > checkErrorAndVisit(expression); >- m_stack.takeLast(); // We don't need to do anything with the result. >+ takeLastValue(); // We don't need to do anything with the result. > }), forLoop.initialization()); > > emitLoop(LoopConditionLocation::BeforeBody, forLoop.condition(), forLoop.increment(), forLoop.body()); >@@ -315,7 +354,7 @@ void FunctionDefinitionWriter::visit(AST > void FunctionDefinitionWriter::visit(AST::IfStatement& ifStatement) > { > checkErrorAndVisit(ifStatement.conditional()); >- m_stringBuilder.append(makeString("if (", m_stack.takeLast(), ") {\n")); >+ m_stringBuilder.append(makeString("if (", takeLastValue(), ") {\n")); > checkErrorAndVisit(ifStatement.body()); > if (ifStatement.elseBody()) { > m_stringBuilder.append("} else {\n"); >@@ -330,10 +369,10 @@ void FunctionDefinitionWriter::visit(AST > checkErrorAndVisit(*returnStatement.value()); > if (m_entryPointScaffolding) { > auto variableName = generateNextVariableName(); >- m_stringBuilder.append(m_entryPointScaffolding->pack(m_stack.takeLast(), variableName)); >+ m_stringBuilder.append(m_entryPointScaffolding->pack(takeLastValue(), variableName)); > m_stringBuilder.append(makeString("return ", variableName, ";\n")); > } else >- m_stringBuilder.append(makeString("return ", m_stack.takeLast(), ";\n")); >+ m_stringBuilder.append(makeString("return ", takeLastValue(), ";\n")); > } else > m_stringBuilder.append("return;\n"); > } >@@ -342,7 +381,7 @@ void FunctionDefinitionWriter::visit(AST > { > checkErrorAndVisit(switchStatement.value()); > >- m_stringBuilder.append(makeString("switch (", m_stack.takeLast(), ") {")); >+ m_stringBuilder.append(makeString("switch (", takeLastValue(), ") {")); > for (auto& switchCase : switchStatement.switchCases()) > checkErrorAndVisit(switchCase); > m_stringBuilder.append("}\n"); >@@ -375,7 +414,7 @@ void FunctionDefinitionWriter::visit(AST > auto variableName = generateNextVariableName(); > auto mangledTypeName = m_typeNamer.mangledNameForType(integerLiteral.resolvedType()); > m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", integerLiteral.value(), ");\n")); >- m_stack.append(variableName); >+ appendRightValue(integerLiteral, variableName); > } > > void FunctionDefinitionWriter::visit(AST::UnsignedIntegerLiteral& unsignedIntegerLiteral) >@@ -383,7 +422,7 @@ void FunctionDefinitionWriter::visit(AST > auto variableName = generateNextVariableName(); > auto mangledTypeName = m_typeNamer.mangledNameForType(unsignedIntegerLiteral.resolvedType()); > m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", unsignedIntegerLiteral.value(), ");\n")); >- m_stack.append(variableName); >+ appendRightValue(unsignedIntegerLiteral, variableName); > } > > void FunctionDefinitionWriter::visit(AST::FloatLiteral& floatLiteral) >@@ -391,7 +430,7 @@ void FunctionDefinitionWriter::visit(AST > auto variableName = generateNextVariableName(); > auto mangledTypeName = m_typeNamer.mangledNameForType(floatLiteral.resolvedType()); > m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", floatLiteral.value(), ");\n")); >- m_stack.append(variableName); >+ appendRightValue(floatLiteral, variableName); > } > > void FunctionDefinitionWriter::visit(AST::NullLiteral& nullLiteral) >@@ -408,7 +447,7 @@ void FunctionDefinitionWriter::visit(AST > else > m_stringBuilder.append("nullptr"); > m_stringBuilder.append(";\n"); >- m_stack.append(variableName); >+ appendRightValue(nullLiteral, variableName); > } > > void FunctionDefinitionWriter::visit(AST::BooleanLiteral& booleanLiteral) >@@ -416,7 +455,7 @@ void FunctionDefinitionWriter::visit(AST > auto variableName = generateNextVariableName(); > auto mangledTypeName = m_typeNamer.mangledNameForType(booleanLiteral.resolvedType()); > m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", booleanLiteral.value() ? "true" : "false", ");\n")); >- m_stack.append(variableName); >+ appendRightValue(booleanLiteral, variableName); > } > > void FunctionDefinitionWriter::visit(AST::EnumerationMemberLiteral& enumerationMemberLiteral) >@@ -426,7 +465,7 @@ void FunctionDefinitionWriter::visit(AST > auto variableName = generateNextVariableName(); > auto mangledTypeName = m_typeNamer.mangledNameForType(enumerationMemberLiteral.resolvedType()); > m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = ", mangledTypeName, '.', m_typeNamer.mangledNameForEnumerationMember(*enumerationMemberLiteral.enumerationMember()), ";\n")); >- m_stack.append(variableName); >+ appendRightValue(enumerationMemberLiteral, variableName); > } > > void FunctionDefinitionWriter::visit(AST::Expression& expression) >@@ -434,37 +473,39 @@ void FunctionDefinitionWriter::visit(AST > Visitor::visit(expression); > } > >-void FunctionDefinitionWriter::visit(AST::DotExpression&) >+void FunctionDefinitionWriter::visit(AST::DotExpression& dotExpression) > { > // This should be lowered already. > // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195788 Replace this with ASSERT_NOT_REACHED(). > notImplemented(); >- m_stack.append("dummy"); >+ appendRightValue(dotExpression, "dummy"); > } > > void FunctionDefinitionWriter::visit(AST::GlobalVariableReference& globalVariableReference) > { >- auto variableName = generateNextVariableName(); >+ auto valueName = generateNextVariableName(); >+ auto pointerName = generateNextVariableName(); > auto mangledTypeName = m_typeNamer.mangledNameForType(globalVariableReference.resolvedType()); > checkErrorAndVisit(globalVariableReference.base()); >- m_stringBuilder.append(makeString("thread ", mangledTypeName, "& ", variableName, " = ", m_stack.takeLast(), "->", m_typeNamer.mangledNameForStructureElement(globalVariableReference.structField()), ";\n")); >- m_stack.append(variableName); >+ m_stringBuilder.append(makeString("thread ", mangledTypeName, "* ", pointerName, " = &", takeLastValue(), "->", m_typeNamer.mangledNameForStructureElement(globalVariableReference.structField()), ";\n")); >+ m_stringBuilder.append(makeString(mangledTypeName, ' ', valueName, " = ", "*", pointerName, ";\n")); >+ appendLeftValue(globalVariableReference, valueName, pointerName); > } > >-void FunctionDefinitionWriter::visit(AST::IndexExpression&) >+void FunctionDefinitionWriter::visit(AST::IndexExpression& indexExpression) > { > // This should be lowered already. > // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195788 Replace this with ASSERT_NOT_REACHED(). > notImplemented(); >- m_stack.append("dummy"); >+ appendRightValue(indexExpression, "dummy"); > } > >-void FunctionDefinitionWriter::visit(AST::PropertyAccessExpression&) >+void FunctionDefinitionWriter::visit(AST::PropertyAccessExpression& propertyAccessExpression) > { > // This should be lowered already. > // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195788 Replace this with ASSERT_NOT_REACHED(). > notImplemented(); >- m_stack.append("dummy"); >+ appendRightValue(propertyAccessExpression, "dummy"); > } > > void FunctionDefinitionWriter::visit(AST::VariableDeclaration& variableDeclaration) >@@ -476,7 +517,7 @@ void FunctionDefinitionWriter::visit(AST > // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198160 Implement qualifiers. > if (variableDeclaration.initializer()) { > checkErrorAndVisit(*variableDeclaration.initializer()); >- m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*variableDeclaration.type()), ' ', variableName, " = ", m_stack.takeLast(), ";\n")); >+ m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*variableDeclaration.type()), ' ', variableName, " = ", takeLastValue(), ";\n")); > } else > m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*variableDeclaration.type()), ' ', variableName, ";\n")); > } >@@ -484,11 +525,11 @@ void FunctionDefinitionWriter::visit(AST > void FunctionDefinitionWriter::visit(AST::AssignmentExpression& assignmentExpression) > { > checkErrorAndVisit(assignmentExpression.left()); >- auto leftName = m_stack.takeLast(); >+ auto pointerName = takeLastLeftValue(); > checkErrorAndVisit(assignmentExpression.right()); >- auto rightName = m_stack.takeLast(); >- m_stringBuilder.append(makeString(leftName, " = ", rightName, ";\n")); >- m_stack.append(rightName); >+ auto rightName = takeLastValue(); >+ m_stringBuilder.append(makeString("if (", pointerName, ") *", pointerName, " = ", rightName, ";\n")); >+ appendRightValue(assignmentExpression, rightName); > } > > void FunctionDefinitionWriter::visit(AST::CallExpression& callExpression) >@@ -496,7 +537,7 @@ void FunctionDefinitionWriter::visit(AST > Vector<String> argumentNames; > for (auto& argument : callExpression.arguments()) { > checkErrorAndVisit(argument); >- argumentNames.append(m_stack.takeLast()); >+ argumentNames.append(takeLastValue()); > } > ASSERT(callExpression.function()); > auto iterator = m_functionMapping.find(callExpression.function()); >@@ -509,7 +550,7 @@ void FunctionDefinitionWriter::visit(AST > m_stringBuilder.append(argumentNames[i]); > } > m_stringBuilder.append(");\n"); >- m_stack.append(variableName); >+ appendRightValue(callExpression, variableName); > } > > void FunctionDefinitionWriter::visit(AST::CommaExpression& commaExpression) >@@ -517,26 +558,30 @@ void FunctionDefinitionWriter::visit(AST > String result; > for (auto& expression : commaExpression.list()) { > checkErrorAndVisit(expression); >- result = m_stack.takeLast(); >+ result = takeLastValue(); > } >- m_stack.append(result); >+ appendRightValue(commaExpression, result); > } > > void FunctionDefinitionWriter::visit(AST::DereferenceExpression& dereferenceExpression) > { > checkErrorAndVisit(dereferenceExpression.pointer()); >- auto right = m_stack.takeLast(); >+ auto right = takeLastValue(); > auto variableName = generateNextVariableName(); >- m_stringBuilder.append(makeString(AST::toString(*dereferenceExpression.typeAnnotation().leftAddressSpace()), ' ', m_typeNamer.mangledNameForType(dereferenceExpression.resolvedType()), "& ", variableName, " = *", right, ";\n")); >- m_stack.append(variableName); >+ auto pointerName = generateNextVariableName(); >+ m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(dereferenceExpression.pointer().resolvedType()), ' ', pointerName, " = ", right, ";\n")); >+ m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(dereferenceExpression.resolvedType()), ' ', variableName, ";\n")); >+ m_stringBuilder.append(makeString("if (", pointerName, ") ", variableName, " = *", right, ";\n")); >+ m_stringBuilder.append(makeString("else ", memsetZeroFunctionName, '(', variableName, ");\n")); >+ appendLeftValue(dereferenceExpression, variableName, pointerName); > } > > void FunctionDefinitionWriter::visit(AST::LogicalExpression& logicalExpression) > { > checkErrorAndVisit(logicalExpression.left()); >- auto left = m_stack.takeLast(); >+ auto left = takeLastValue(); > checkErrorAndVisit(logicalExpression.right()); >- auto right = m_stack.takeLast(); >+ auto right = takeLastValue(); > auto variableName = generateNextVariableName(); > m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(logicalExpression.resolvedType()), ' ', variableName, " = ", left)); > switch (logicalExpression.type()) { >@@ -549,22 +594,24 @@ void FunctionDefinitionWriter::visit(AST > break; > } > m_stringBuilder.append(makeString(right, ";\n")); >- m_stack.append(variableName); >+ appendRightValue(logicalExpression, variableName); > } > > void FunctionDefinitionWriter::visit(AST::LogicalNotExpression& logicalNotExpression) > { > checkErrorAndVisit(logicalNotExpression.operand()); >- auto operand = m_stack.takeLast(); >+ auto operand = takeLastValue(); > auto variableName = generateNextVariableName(); > m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(logicalNotExpression.resolvedType()), ' ', variableName, " = !", operand, ";\n")); >- m_stack.append(variableName); >+ appendRightValue(logicalNotExpression, variableName); > } > > void FunctionDefinitionWriter::visit(AST::MakeArrayReferenceExpression& makeArrayReferenceExpression) > { > checkErrorAndVisit(makeArrayReferenceExpression.leftValue()); >- auto lValue = m_stack.takeLast(); >+ // FIXME: This needs to be made to work. It probably should be using the last leftValue too. >+ // https://bugs.webkit.org/show_bug.cgi?id=198838 >+ auto lValue = takeLastValue(); > auto variableName = generateNextVariableName(); > auto mangledTypeName = m_typeNamer.mangledNameForType(makeArrayReferenceExpression.resolvedType()); > if (is<AST::PointerType>(makeArrayReferenceExpression.resolvedType())) >@@ -574,16 +621,16 @@ void FunctionDefinitionWriter::visit(AST > m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = { &(", lValue, "[0]), ", arrayType.numElements(), " };\n")); > } else > m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = { &", lValue, ", 1 };\n")); >- m_stack.append(variableName); >+ appendRightValue(makeArrayReferenceExpression, variableName); > } > > void FunctionDefinitionWriter::visit(AST::MakePointerExpression& makePointerExpression) > { > checkErrorAndVisit(makePointerExpression.leftValue()); >- auto lValue = m_stack.takeLast(); >+ auto pointer = takeLastLeftValue(); > auto variableName = generateNextVariableName(); >- m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(makePointerExpression.resolvedType()), ' ', variableName, " = &", lValue, ";\n")); >- m_stack.append(variableName); >+ m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(makePointerExpression.resolvedType()), ' ', variableName, " = ", pointer, ";\n")); >+ appendRightValue(makePointerExpression, variableName); > } > > void FunctionDefinitionWriter::visit(AST::ReadModifyWriteExpression&) >@@ -595,19 +642,19 @@ void FunctionDefinitionWriter::visit(AST > void FunctionDefinitionWriter::visit(AST::TernaryExpression& ternaryExpression) > { > checkErrorAndVisit(ternaryExpression.predicate()); >- auto check = m_stack.takeLast(); >+ auto check = takeLastValue(); > > auto variableName = generateNextVariableName(); > m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(ternaryExpression.resolvedType()), ' ', variableName, ";\n")); > > m_stringBuilder.append(makeString("if (", check, ") {\n")); > checkErrorAndVisit(ternaryExpression.bodyExpression()); >- m_stringBuilder.append(makeString(variableName, " = ", m_stack.takeLast(), ";\n")); >+ m_stringBuilder.append(makeString(variableName, " = ", takeLastValue(), ";\n")); > m_stringBuilder.append("} else {\n"); > checkErrorAndVisit(ternaryExpression.elseExpression()); >- m_stringBuilder.append(makeString(variableName, " = ", m_stack.takeLast(), ";\n")); >+ m_stringBuilder.append(makeString(variableName, " = ", takeLastValue(), ";\n")); > m_stringBuilder.append("}\n"); >- m_stack.append(variableName); >+ appendRightValue(ternaryExpression, variableName); > } > > void FunctionDefinitionWriter::visit(AST::VariableReference& variableReference) >@@ -615,7 +662,9 @@ void FunctionDefinitionWriter::visit(AST > ASSERT(variableReference.variable()); > auto iterator = m_variableMapping.find(variableReference.variable()); > ASSERT(iterator != m_variableMapping.end()); >- m_stack.append(iterator->value); >+ auto pointerName = generateNextVariableName(); >+ m_stringBuilder.append(makeString("thread ", m_typeNamer.mangledNameForType(variableReference.resolvedType()), "* ", pointerName, " = &", iterator->value, ";\n")); >+ appendLeftValue(variableReference, iterator->value, pointerName); > } > > String FunctionDefinitionWriter::constantExpressionString(AST::ConstantExpression& constantExpression) >Index: Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp (working copy) >@@ -81,7 +81,7 @@ static String atomicName(String input) > return "fetch_xor"_str; > } > >-String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclaration, String& outputFunctionName, Intrinsics& intrinsics, TypeNamer& typeNamer) >+String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclaration, String& outputFunctionName, Intrinsics& intrinsics, TypeNamer& typeNamer, const char* memsetZeroFunctionName) > { > StringBuilder stringBuilder; > if (nativeFunctionDeclaration.isCast()) { >@@ -89,8 +89,7 @@ String writeNativeFunction(AST::NativeFu > if (!nativeFunctionDeclaration.parameters().size()) { > stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, "() {\n")); > stringBuilder.append(makeString(" ", metalReturnName, " x;\n")); >- stringBuilder.append(" thread char* ptr = static_cast<thread char*>(static_cast<thread void*>(&x));\n"); >- stringBuilder.append(makeString(" for (size_t i = 0; i < sizeof(", metalReturnName, "); ++i) ptr[i] = 0;\n")); >+ stringBuilder.append(makeString(" ", memsetZeroFunctionName, "(x);\n")); > stringBuilder.append(" return x;\n"); > stringBuilder.append("}\n"); > return stringBuilder.toString(); >@@ -215,38 +214,14 @@ String writeNativeFunction(AST::NativeFu > return stringBuilder.toString(); > } > >- if (nativeFunctionDeclaration.name() == "operator[]") { >- ASSERT(nativeFunctionDeclaration.parameters().size() == 2); >- auto metalParameter1Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type()); >- auto metalParameter2Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[1]->type()); >- auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type()); >- stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " m, ", metalParameter2Name, " i) {\n")); >- stringBuilder.append(makeString(" return m[i];\n")); >- stringBuilder.append("}\n"); >- return stringBuilder.toString(); >- } >- > if (nativeFunctionDeclaration.name() == "operator&[]") { > ASSERT(nativeFunctionDeclaration.parameters().size() == 2); > auto metalParameter1Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type()); > auto metalParameter2Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[1]->type()); > auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type()); >- auto fieldName = nativeFunctionDeclaration.name().substring("operator&[]."_str.length()); > stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " v, ", metalParameter2Name, " n) {\n")); >- stringBuilder.append(makeString(" return &(v.pointer[n]);\n")); >- stringBuilder.append("}\n"); >- return stringBuilder.toString(); >- } >- >- if (nativeFunctionDeclaration.name() == "operator[]=") { >- ASSERT(nativeFunctionDeclaration.parameters().size() == 3); >- auto metalParameter1Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type()); >- auto metalParameter2Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[1]->type()); >- auto metalParameter3Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[2]->type()); >- auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type()); >- stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " m, ", metalParameter2Name, " i, ", metalParameter3Name, " v) {\n")); >- stringBuilder.append(makeString(" m[i] = v;\n")); >- stringBuilder.append(makeString(" return m;\n")); >+ stringBuilder.append(" if (n < v.length) return &(v.pointer[n]);\n"); >+ stringBuilder.append(" return nullptr;\n"); > stringBuilder.append("}\n"); > return stringBuilder.toString(); > } >Index: Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.h (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.h (working copy) >@@ -45,7 +45,7 @@ namespace Metal { > > class TypeNamer; > >-String writeNativeFunction(AST::NativeFunctionDeclaration&, String& outputFunctionName, Intrinsics&, TypeNamer&); >+String writeNativeFunction(AST::NativeFunctionDeclaration&, String& outputFunctionName, Intrinsics&, TypeNamer&, const char* memsetZeroFunctionName); > > } > >Index: Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp (working copy) >@@ -396,7 +396,7 @@ void TypeNamer::emitUnnamedTypeDefinitio > ASSERT(baseTypeNameNode.parent()); > stringBuilder.append(makeString("struct ", arrayReferenceType.mangledName(), "{ \n")); > stringBuilder.append(makeString(" ", toString(arrayReferenceType.addressSpace()), " ", arrayReferenceType.parent()->mangledName(), "* pointer;\n")); >- stringBuilder.append(" uint length;\n"); >+ stringBuilder.append(" uint32_t length;\n"); > stringBuilder.append("};\n"); > } else { > ASSERT(is<ArrayTypeNameNode>(baseTypeNameNode)); >Index: Source/WebCore/platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm >=================================================================== >--- Source/WebCore/platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm (revision 246404) >+++ Source/WebCore/platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm (working copy) >@@ -92,8 +92,9 @@ static Optional<WHLSL::ComputeDimensions > BEGIN_BLOCK_OBJC_EXCEPTIONS; > computeLibrary = adoptNS([device.platformDevice() newLibraryWithSource:whlslCompileResult->metalSource options:nil error:&error]); > END_BLOCK_OBJC_EXCEPTIONS; >- > ASSERT(computeLibrary); >+ if (!computeLibrary) >+ NSLog(@"%@", error); > // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195771 Once we zero-fill variables, there should be no warnings, so we should be able to ASSERT(!error) here. > > computeEntryPoint = whlslCompileResult->mangledEntryPointName; >Index: Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm >=================================================================== >--- Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm (revision 246404) >+++ Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm (working copy) >@@ -417,6 +417,8 @@ static bool trySetFunctions(const char* > END_BLOCK_OBJC_EXCEPTIONS; > > ASSERT(vertexLibrary); >+ if (!vertexLibrary) >+ NSLog(@"%@", error); > // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195771 Once we zero-fill variables, there should be no warnings, so we should be able to ASSERT(!error) here. > > fragmentLibrary = vertexLibrary; >Index: LayoutTests/ChangeLog >=================================================================== >--- LayoutTests/ChangeLog (revision 246404) >+++ LayoutTests/ChangeLog (working copy) >@@ -1,3 +1,16 @@ >+2019-06-13 Saam Barati <sbarati@apple.com> >+ >+ [WHLSL] Implement out-of-bounds and nullptr behavior >+ https://bugs.webkit.org/show_bug.cgi?id=198600 >+ <rdar://problem/51668853> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * webgpu/whlsl-null-dereference-expected.txt: Added. >+ * webgpu/whlsl-null-dereference.html: Added. >+ * webgpu/whlsl-oob-access-expected.txt: Added. >+ * webgpu/whlsl-oob-access.html: Added. >+ > 2019-06-13 Antoine Quint <graouts@apple.com> > > "display: contents" Content click does not trigger >Index: LayoutTests/webgpu/whlsl-duplicate-types-should-not-produce-duplicate-ctors-expected.txt >=================================================================== >--- LayoutTests/webgpu/whlsl-duplicate-types-should-not-produce-duplicate-ctors-expected.txt (nonexistent) >+++ LayoutTests/webgpu/whlsl-duplicate-types-should-not-produce-duplicate-ctors-expected.txt (working copy) >@@ -0,0 +1,12 @@ >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+PASS resultsFloat32Array[0] is 2 >+PASS resultsFloat32Array[1] is 4 >+PASS resultsFloat32Array[2] is 6 >+PASS resultsFloat32Array[3] is 8 >+PASS resultsFloat32Array[4] is 5 >+PASS resultsFloat32Array[5] is 6 >+PASS resultsFloat32Array[6] is 7 >+PASS resultsFloat32Array[7] is 8 >+ >Index: LayoutTests/webgpu/whlsl-duplicate-types-should-not-produce-duplicate-ctors.html >=================================================================== >--- LayoutTests/webgpu/whlsl-duplicate-types-should-not-produce-duplicate-ctors.html (nonexistent) >+++ LayoutTests/webgpu/whlsl-duplicate-types-should-not-produce-duplicate-ctors.html (working copy) >@@ -0,0 +1,107 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<script src="../resources/js-test-pre.js"></script> >+</head> >+<body> >+<script> >+const shaderSource = ` >+struct XYZ { >+ int x; >+ int y; >+ int z; >+} >+ >+typedef XYZ1 = XYZ; >+typedef XYZ2 = XYZ; >+typedef XYZ3 = XYZ; >+ >+[numthreads(2, 1, 1)] >+compute void computeShader(device float[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ thread int* x; >+ thread int* y; >+ thread float* f1; >+ thread float* f2; >+ XYZ1 a; >+ XYZ2 b; >+ XYZ3 c; >+ if (*x == *y && x == y && x == null && f1 == null && *f1 == 0) { >+ buffer[uint(threadID.x)] = buffer[uint(threadID.x)] * 2.0; >+ } >+} >+`; >+let resultsFloat32Array; >+async function start() { >+ const adapter = await navigator.gpu.requestAdapter(); >+ const device = await adapter.requestDevice(); >+ >+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true}); >+ const computeStage = {module: shaderModule, entryPoint: "computeShader"}; >+ >+ const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "storage-buffer"}]}; >+ const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor); >+ const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const computePipelineDescriptor = {computeStage, layout: pipelineLayout}; >+ const computePipeline = device.createComputePipeline(computePipelineDescriptor); >+ >+ const bufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 8, usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.TRANSFER_SRC}; >+ const buffer = device.createBuffer(bufferDescriptor); >+ const bufferArrayBuffer = await buffer.mapWriteAsync(); >+ const bufferFloat32Array = new Float32Array(bufferArrayBuffer); >+ bufferFloat32Array[0] = 1; >+ bufferFloat32Array[1] = 2; >+ bufferFloat32Array[2] = 3; >+ bufferFloat32Array[3] = 4; >+ bufferFloat32Array[4] = 5; >+ bufferFloat32Array[5] = 6; >+ bufferFloat32Array[6] = 7; >+ bufferFloat32Array[7] = 8; >+ buffer.unmap(); >+ >+ const resultsBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 8, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_READ}; >+ const resultsBuffer = device.createBuffer(resultsBufferDescriptor); >+ >+ const bufferBinding = {buffer: resultsBuffer, size: 4}; >+ const bindGroupBinding = {binding: 0, resource: bufferBinding}; >+ const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]}; >+ const bindGroup = device.createBindGroup(bindGroupDescriptor); >+ >+ const commandEncoder = device.createCommandEncoder(); // {} >+ commandEncoder.copyBufferToBuffer(buffer, 0, resultsBuffer, 0, Float32Array.BYTES_PER_ELEMENT * 8); >+ const computePassEncoder = commandEncoder.beginComputePass(); >+ computePassEncoder.setPipeline(computePipeline); >+ computePassEncoder.setBindGroup(0, bindGroup); >+ computePassEncoder.dispatch(2, 1, 1); >+ computePassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ const resultsArrayBuffer = await resultsBuffer.mapReadAsync(); >+ resultsFloat32Array = new Float32Array(resultsArrayBuffer); >+ shouldBe("resultsFloat32Array[0]", "2"); >+ shouldBe("resultsFloat32Array[1]", "4"); >+ shouldBe("resultsFloat32Array[2]", "6"); >+ shouldBe("resultsFloat32Array[3]", "8"); >+ shouldBe("resultsFloat32Array[4]", "5"); >+ shouldBe("resultsFloat32Array[5]", "6"); >+ shouldBe("resultsFloat32Array[6]", "7"); >+ shouldBe("resultsFloat32Array[7]", "8"); >+ resultsBuffer.unmap(); >+} >+if (window.testRunner) >+ testRunner.waitUntilDone(); >+window.addEventListener("load", function() { >+ start().then(function() { >+ if (window.testRunner) >+ testRunner.notifyDone(); >+ }, function() { >+ if (window.testRunner) >+ testRunner.notifyDone(); >+ }); >+}); >+</script> >+<script src="../resources/js-test-post.js"></script> >+</body> >+</html> >Index: LayoutTests/webgpu/whlsl-null-dereference-expected.txt >=================================================================== >--- LayoutTests/webgpu/whlsl-null-dereference-expected.txt (nonexistent) >+++ LayoutTests/webgpu/whlsl-null-dereference-expected.txt (working copy) >@@ -0,0 +1,12 @@ >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+PASS resultsFloat32Array[0] is 2 >+PASS resultsFloat32Array[1] is 4 >+PASS resultsFloat32Array[2] is 6 >+PASS resultsFloat32Array[3] is 8 >+PASS resultsFloat32Array[4] is 5 >+PASS resultsFloat32Array[5] is 6 >+PASS resultsFloat32Array[6] is 7 >+PASS resultsFloat32Array[7] is 8 >+ >Index: LayoutTests/webgpu/whlsl-null-dereference.html >=================================================================== >--- LayoutTests/webgpu/whlsl-null-dereference.html (nonexistent) >+++ LayoutTests/webgpu/whlsl-null-dereference.html (working copy) >@@ -0,0 +1,124 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<script src="../resources/js-test-pre.js"></script> >+</head> >+<body> >+<script> >+const shaderSource = ` >+typedef Foo = thread int*; >+Foo getNullPtr() >+{ >+ return null; >+} >+ >+struct XYZ { >+ float x; >+ float y; >+ float z; >+} >+ >+[numthreads(2, 1, 1)] >+compute void computeShader(device float[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ Foo ptr = null; >+ *ptr = 42; >+ *getNullPtr() = 42; >+ if (*ptr == 0) { >+ if (ptr == getNullPtr()) { >+ if (*getNullPtr() == 0) { >+ thread XYZ* xyzPtr = null; >+ XYZ xyz; >+ xyz.x = 1; >+ xyz.y = 1; >+ xyz.z = 1; >+ if (xyz.z == 1.0 && xyz.y == 1.0 && xyz.z == 1.0) { >+ *xyzPtr = xyz; >+ xyz = *xyzPtr; >+ if (xyz.z == 0.0 && xyz.y == 0.0 && xyz.z == 0.0) { >+ if (&*getNullPtr() == null) { >+ if (&*(&*getNullPtr()) == null) { >+ buffer[uint(threadID.x)] = buffer[uint(threadID.x)] * 2.0; >+ } >+ } >+ } >+ } >+ } >+ } >+ } >+} >+`; >+let resultsFloat32Array; >+async function start() { >+ const adapter = await navigator.gpu.requestAdapter(); >+ const device = await adapter.requestDevice(); >+ >+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true}); >+ const computeStage = {module: shaderModule, entryPoint: "computeShader"}; >+ >+ const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "storage-buffer"}]}; >+ const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor); >+ const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const computePipelineDescriptor = {computeStage, layout: pipelineLayout}; >+ const computePipeline = device.createComputePipeline(computePipelineDescriptor); >+ >+ const bufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 8, usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.TRANSFER_SRC}; >+ const buffer = device.createBuffer(bufferDescriptor); >+ const bufferArrayBuffer = await buffer.mapWriteAsync(); >+ const bufferFloat32Array = new Float32Array(bufferArrayBuffer); >+ bufferFloat32Array[0] = 1; >+ bufferFloat32Array[1] = 2; >+ bufferFloat32Array[2] = 3; >+ bufferFloat32Array[3] = 4; >+ bufferFloat32Array[4] = 5; >+ bufferFloat32Array[5] = 6; >+ bufferFloat32Array[6] = 7; >+ bufferFloat32Array[7] = 8; >+ buffer.unmap(); >+ >+ const resultsBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 8, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_READ}; >+ const resultsBuffer = device.createBuffer(resultsBufferDescriptor); >+ >+ const bufferBinding = {buffer: resultsBuffer, size: 4}; >+ const bindGroupBinding = {binding: 0, resource: bufferBinding}; >+ const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]}; >+ const bindGroup = device.createBindGroup(bindGroupDescriptor); >+ >+ const commandEncoder = device.createCommandEncoder(); // {} >+ commandEncoder.copyBufferToBuffer(buffer, 0, resultsBuffer, 0, Float32Array.BYTES_PER_ELEMENT * 8); >+ const computePassEncoder = commandEncoder.beginComputePass(); >+ computePassEncoder.setPipeline(computePipeline); >+ computePassEncoder.setBindGroup(0, bindGroup); >+ computePassEncoder.dispatch(2, 1, 1); >+ computePassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ const resultsArrayBuffer = await resultsBuffer.mapReadAsync(); >+ resultsFloat32Array = new Float32Array(resultsArrayBuffer); >+ shouldBe("resultsFloat32Array[0]", "2"); >+ shouldBe("resultsFloat32Array[1]", "4"); >+ shouldBe("resultsFloat32Array[2]", "6"); >+ shouldBe("resultsFloat32Array[3]", "8"); >+ shouldBe("resultsFloat32Array[4]", "5"); >+ shouldBe("resultsFloat32Array[5]", "6"); >+ shouldBe("resultsFloat32Array[6]", "7"); >+ shouldBe("resultsFloat32Array[7]", "8"); >+ resultsBuffer.unmap(); >+} >+if (window.testRunner) >+ testRunner.waitUntilDone(); >+window.addEventListener("load", function() { >+ start().then(function() { >+ if (window.testRunner) >+ testRunner.notifyDone(); >+ }, function() { >+ if (window.testRunner) >+ testRunner.notifyDone(); >+ }); >+}); >+</script> >+<script src="../resources/js-test-post.js"></script> >+</body> >+</html> >Index: LayoutTests/webgpu/whlsl-oob-access-expected.txt >=================================================================== >--- LayoutTests/webgpu/whlsl-oob-access-expected.txt (nonexistent) >+++ LayoutTests/webgpu/whlsl-oob-access-expected.txt (working copy) >@@ -0,0 +1,12 @@ >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+PASS resultsFloat32Array[0] is 2 >+PASS resultsFloat32Array[1] is 4 >+PASS resultsFloat32Array[2] is 6 >+PASS resultsFloat32Array[3] is 8 >+PASS resultsFloat32Array[4] is 5 >+PASS resultsFloat32Array[5] is 6 >+PASS resultsFloat32Array[6] is 7 >+PASS resultsFloat32Array[7] is 8 >+ >Index: LayoutTests/webgpu/whlsl-oob-access.html >=================================================================== >--- LayoutTests/webgpu/whlsl-oob-access.html (nonexistent) >+++ LayoutTests/webgpu/whlsl-oob-access.html (working copy) >@@ -0,0 +1,91 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<script src="../resources/js-test-pre.js"></script> >+</head> >+<body> >+<script> >+const shaderSource = ` >+[numthreads(2, 1, 1)] >+compute void computeShader(device float[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ buffer[1337] = 0.0; >+ buffer[42424242] = 0.0; >+ if (buffer[100000] == 0.0) >+ buffer[uint(threadID.x)] = buffer[uint(threadID.x)] * 2.0; >+} >+`; >+let resultsFloat32Array; >+async function start() { >+ const adapter = await navigator.gpu.requestAdapter(); >+ const device = await adapter.requestDevice(); >+ >+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true}); >+ const computeStage = {module: shaderModule, entryPoint: "computeShader"}; >+ >+ const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "storage-buffer"}]}; >+ const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor); >+ const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const computePipelineDescriptor = {computeStage, layout: pipelineLayout}; >+ const computePipeline = device.createComputePipeline(computePipelineDescriptor); >+ >+ const bufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 8, usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.TRANSFER_SRC}; >+ const buffer = device.createBuffer(bufferDescriptor); >+ const bufferArrayBuffer = await buffer.mapWriteAsync(); >+ const bufferFloat32Array = new Float32Array(bufferArrayBuffer); >+ bufferFloat32Array[0] = 1; >+ bufferFloat32Array[1] = 2; >+ bufferFloat32Array[2] = 3; >+ bufferFloat32Array[3] = 4; >+ bufferFloat32Array[4] = 5; >+ bufferFloat32Array[5] = 6; >+ bufferFloat32Array[6] = 7; >+ bufferFloat32Array[7] = 8; >+ buffer.unmap(); >+ >+ const resultsBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 8, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_READ}; >+ const resultsBuffer = device.createBuffer(resultsBufferDescriptor); >+ >+ const bufferBinding = {buffer: resultsBuffer, size: 4}; >+ const bindGroupBinding = {binding: 0, resource: bufferBinding}; >+ const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]}; >+ const bindGroup = device.createBindGroup(bindGroupDescriptor); >+ >+ const commandEncoder = device.createCommandEncoder(); // {} >+ commandEncoder.copyBufferToBuffer(buffer, 0, resultsBuffer, 0, Float32Array.BYTES_PER_ELEMENT * 8); >+ const computePassEncoder = commandEncoder.beginComputePass(); >+ computePassEncoder.setPipeline(computePipeline); >+ computePassEncoder.setBindGroup(0, bindGroup); >+ computePassEncoder.dispatch(2, 1, 1); >+ computePassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ const resultsArrayBuffer = await resultsBuffer.mapReadAsync(); >+ resultsFloat32Array = new Float32Array(resultsArrayBuffer); >+ shouldBe("resultsFloat32Array[0]", "2"); >+ shouldBe("resultsFloat32Array[1]", "4"); >+ shouldBe("resultsFloat32Array[2]", "6"); >+ shouldBe("resultsFloat32Array[3]", "8"); >+ shouldBe("resultsFloat32Array[4]", "5"); >+ shouldBe("resultsFloat32Array[5]", "6"); >+ shouldBe("resultsFloat32Array[6]", "7"); >+ shouldBe("resultsFloat32Array[7]", "8"); >+ resultsBuffer.unmap(); >+} >+if (window.testRunner) >+ testRunner.waitUntilDone(); >+window.addEventListener("load", function() { >+ start().then(function() { >+ if (window.testRunner) >+ testRunner.notifyDone(); >+ }, function() { >+ if (window.testRunner) >+ testRunner.notifyDone(); >+ }); >+}); >+</script> >+<script src="../resources/js-test-post.js"></script> >+</body> >+</html>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 198580
:
372083
|
372131
|
372134
|
372312
|
372348