WebKit Bugzilla
Attachment 370916 Details for
Bug 195794
: [WHLSL] Enforce variable lifetimes
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
patch
b-backup.diff (text/plain), 60.63 KB, created by
Saam Barati
on 2019-05-29 20:19:01 PDT
(
hide
)
Description:
patch
Filename:
MIME Type:
Creator:
Saam Barati
Created:
2019-05-29 20:19:01 PDT
Size:
60.63 KB
patch
obsolete
>Index: Source/WTF/ChangeLog >=================================================================== >--- Source/WTF/ChangeLog (revision 245882) >+++ Source/WTF/ChangeLog (working copy) >@@ -1,3 +1,13 @@ >+2019-05-29 Saam Barati <sbarati@apple.com> >+ >+ [WHLSL] Enforce variable lifetimes >+ https://bugs.webkit.org/show_bug.cgi?id=195794 >+ <rdar://problem/50746293> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * wtf/PrintStream.h: >+ > 2019-05-29 David Kilzer <ddkilzer@apple.com> > > Clean up a few #include statements in WTF >Index: Source/WTF/wtf/PrintStream.h >=================================================================== >--- Source/WTF/wtf/PrintStream.h (revision 245830) >+++ Source/WTF/wtf/PrintStream.h (working copy) >@@ -132,7 +132,7 @@ void printInternal(PrintStream& out, con > #define MAKE_PRINT_ADAPTOR(Name, Type, function) \ > class Name { \ > public: \ >- Name(const Type& value) \ >+ Name(Type value) \ > : m_value(value) \ > { \ > } \ >Index: Source/WebCore/ChangeLog >=================================================================== >--- Source/WebCore/ChangeLog (revision 245830) >+++ Source/WebCore/ChangeLog (working copy) >@@ -1,3 +1,88 @@ >+2019-05-29 Saam Barati <sbarati@apple.com> >+ >+ [WHLSL] Enforce variable lifetimes >+ https://bugs.webkit.org/show_bug.cgi?id=195794 >+ <rdar://problem/50746293> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ In WHLSL, each variable has global lifetime. So returning a pointer to a >+ local variable is a legitimate and well specified thing to do. Each local >+ variable has a unique place in memory. So, for example: >+ >+ ``` >+ thread int* ptr() { int local; return &local; } >+ thread int* ptrPtr() { return ptr(); } >+ ``` >+ >+ In the above program, ptr() must always return the same value >+ as ptrPtr(). So, the following would print "42": >+ ``` >+ *ptr() = 42; >+ print(*ptrPtr()); >+ ``` >+ >+ To implement these semantics, this patch introduces a new pass which does the >+ following transformations: >+ - It notes every variable whose address is taken in the program. >+ - Each such variable gets defined as a field in a struct. >+ - Each function which is an entry point defines this struct. >+ - Each non entry point takes a pointer to this struct as its final parameter. >+ - Each call is rewritten to pass a pointer to the struct as the last call argument. >+ - Each variable reference to "x", where "x" ends up in the struct, is >+ modified to instead be "struct->x". We store to "struct->x" after declaring >+ "x". If "x" is a function parameter, we store to "struct->x" as the first >+ thing we do in the function body. >+ >+ Tests: webgpu/whlsl-ensure-proper-variable-lifetime-2.html >+ webgpu/whlsl-ensure-proper-variable-lifetime.html >+ >+ * Modules/webgpu/WHLSL/AST/WHLSLAST.h: >+ * Modules/webgpu/WHLSL/AST/WHLSLExpression.h: >+ (WebCore::WHLSL::AST::Expression::Expression): >+ (WebCore::WHLSL::AST::Expression::isGlobalVariableReference const): >+ (WebCore::WHLSL::AST::Expression::origin const): Deleted. >+ * Modules/webgpu/WHLSL/AST/WHLSLFunctionDeclaration.h: >+ (WebCore::WHLSL::AST::FunctionDeclaration::origin): >+ * Modules/webgpu/WHLSL/AST/WHLSLGlobalVariableReference.h: Added. >+ (WebCore::WHLSL::AST::GlobalVariableReference::GlobalVariableReference): >+ (WebCore::WHLSL::AST::GlobalVariableReference::structField): >+ (WebCore::WHLSL::AST::GlobalVariableReference::base): >+ * Modules/webgpu/WHLSL/AST/WHLSLStatement.h: >+ (WebCore::WHLSL::AST::Statement::Statement): >+ (WebCore::WHLSL::AST::Statement::isWhileLoop const): >+ * Modules/webgpu/WHLSL/AST/WHLSLValue.h: >+ (WebCore::WHLSL::AST::Value::Value): >+ (WebCore::WHLSL::AST::Value::origin const): >+ * Modules/webgpu/WHLSL/AST/WHLSLVariableDeclaration.h: >+ (WebCore::WHLSL::AST::VariableDeclaration::VariableDeclaration): >+ (WebCore::WHLSL::AST::VariableDeclaration::takeInitializer): >+ (WebCore::WHLSL::AST::VariableDeclaration::origin const): Deleted. >+ * Modules/webgpu/WHLSL/AST/WHLSLVariableReference.h: >+ (WebCore::WHLSL::AST::VariableReference::wrap): >+ * Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp: >+ (WebCore::WHLSL::Metal::FunctionDefinitionWriter::visit): >+ * Modules/webgpu/WHLSL/WHLSLASTDumper.cpp: >+ (WebCore::WHLSL::ASTDumper::visit): >+ * Modules/webgpu/WHLSL/WHLSLASTDumper.h: >+ (WebCore::WHLSL::dumpASTNode): >+ (WebCore::WHLSL::dumpAST): >+ (WebCore::WHLSL::toString): Deleted. >+ * Modules/webgpu/WHLSL/WHLSLPrepare.cpp: >+ (WebCore::WHLSL::prepareShared): >+ * Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp: Added. >+ (WebCore::WHLSL::EscapedVariableCollector::takeEscapedVariables): >+ (WebCore::WHLSL::anonymousToken): >+ (WebCore::WHLSL::PreserveLifetimes::PreserveLifetimes): >+ (WebCore::WHLSL::PreserveLifetimes::makeStructVariableReference): >+ (WebCore::WHLSL::preserveVariableLifetimes): >+ * Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.h: Added. >+ * Modules/webgpu/WHLSL/WHLSLVisitor.cpp: >+ (WebCore::WHLSL::Visitor::visit): >+ * Modules/webgpu/WHLSL/WHLSLVisitor.h: >+ * Sources.txt: >+ * WebCore.xcodeproj/project.pbxproj: >+ > 2019-05-28 Shawn Roberts <sroberts@apple.com> > > Unreviewed, rolling out r245475. >Index: Source/WebCore/Sources.txt >=================================================================== >--- Source/WebCore/Sources.txt (revision 245830) >+++ Source/WebCore/Sources.txt (working copy) >@@ -322,6 +322,7 @@ Modules/webgpu/WHLSL/WHLSLIntrinsics.cpp > Modules/webgpu/WHLSL/WHLSLStatementBehaviorChecker.cpp > Modules/webgpu/WHLSL/WHLSLNameContext.cpp > Modules/webgpu/WHLSL/WHLSLNameResolver.cpp >+Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp > Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.cpp > Modules/webgpu/WHLSL/WHLSLRecursionChecker.cpp > Modules/webgpu/WHLSL/WHLSLVisitor.cpp >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLASTDumper.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLASTDumper.cpp (revision 245881) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLASTDumper.cpp (working copy) >@@ -441,6 +441,12 @@ void ASTDumper::visit(AST::DotExpression > m_out.print(".", dotExpression.fieldName()); > } > >+void ASTDumper::visit(AST::GlobalVariableReference& globalVariableReference) >+{ >+ visit(globalVariableReference.base()); >+ m_out.print("=>", globalVariableReference.structField().name()); >+} >+ > void ASTDumper::visit(AST::IndexExpression& indexExpression) > { > visit(static_cast<AST::PropertyAccessExpression&>(indexExpression)); >@@ -529,7 +535,12 @@ void ASTDumper::visit(AST::VariableDecla > visit(*variableDeclaration.type()); > m_out.print(" "); > } >- m_out.print(variableDeclaration.name()); >+ >+ if (variableDeclaration.name().isEmpty()) >+ m_out.print("$", RawPointer(&variableDeclaration)); >+ else >+ m_out.print(variableDeclaration.name()); >+ > if (variableDeclaration.semantic()) > visit(*variableDeclaration.semantic()); > if (variableDeclaration.initializer()) { >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLASTDumper.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLASTDumper.h (revision 245881) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLASTDumper.h (working copy) >@@ -44,7 +44,6 @@ public: > > String toString() { return m_out.toString(); } > >-private: > void visit(AST::UnnamedType&) override; > void visit(AST::NamedType&) override; > void visit(AST::TypeDefinition&) override; >@@ -88,6 +87,7 @@ private: > void visit(AST::DoWhileLoop&) override; > void visit(AST::Expression&) override; > void visit(AST::DotExpression&) override; >+ void visit(AST::GlobalVariableReference&) override; > void visit(AST::IndexExpression&) override; > void visit(AST::PropertyAccessExpression&) override; > void visit(AST::EffectfulExpressionStatement&) override; >@@ -113,6 +113,7 @@ private: > void visit(AST::TernaryExpression&) override; > void visit(AST::VariableReference&) override; > >+private: > struct Indent { > Indent(ASTDumper& dumper) > : m_scope(dumper.m_indent, dumper.m_indent + " ") >@@ -128,16 +129,23 @@ private: > String m_indent; > }; > >-static ALWAYS_INLINE String toString(Program& program) >+template <typename T> >+ALWAYS_INLINE void dumpASTNode(PrintStream& out, T& value) > { > ASTDumper dumper; >- dumper.visit(program); >- return dumper.toString(); >+ dumper.visit(value); >+ out.print(dumper.toString()); > } >+MAKE_PRINT_ADAPTOR(ExpressionDumper, AST::Expression&, dumpASTNode); >+MAKE_PRINT_ADAPTOR(StatementDumper, AST::Statement&, dumpASTNode); >+MAKE_PRINT_ADAPTOR(ProgramDumper, Program&, dumpASTNode); >+MAKE_PRINT_ADAPTOR(StructureDefinitionDumper, AST::StructureDefinition&, dumpASTNode); >+MAKE_PRINT_ADAPTOR(FunctionDefinitionDumper, AST::FunctionDefinition&, dumpASTNode); >+ > > static ALWAYS_INLINE void dumpAST(Program& program) > { >- dataLogLn(toString(program)); >+ dataLogLn(ProgramDumper(program)); > } > > } // namespace WHLSL >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp (revision 245881) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp (working copy) >@@ -37,6 +37,7 @@ > #include "WHLSLMetalCodeGenerator.h" > #include "WHLSLNameResolver.h" > #include "WHLSLParser.h" >+#include "WHLSLPreserveVariableLifetimes.h" > #include "WHLSLProgram.h" > #include "WHLSLPropertyResolver.h" > #include "WHLSLRecursionChecker.h" >@@ -56,7 +57,9 @@ namespace WHLSL { > > static constexpr bool dumpASTBeforeEachPass = false; > static constexpr bool dumpASTAfterParsing = false; >-static constexpr bool dumpASTAtEnd = false; >+static constexpr bool dumpASTAtEnd = true; >+static constexpr bool alwaysDumpPassFailures = false; >+static constexpr bool dumpPassFailure = dumpASTBeforeEachPass || dumpASTAfterParsing || dumpASTAtEnd || alwaysDumpPassFailures; > > static bool dumpASTIfNeeded(bool shouldDump, Program& program, const char* message) > { >@@ -87,8 +90,11 @@ static bool dumpASTAtEndIfNeeded(Program > #define RUN_PASS(pass, ...) \ > do { \ > dumpASTBetweenEachPassIfNeeded(program, "AST before " # pass); \ >- if (!pass(__VA_ARGS__)) \ >+ if (!pass(__VA_ARGS__)) { \ >+ if (dumpPassFailure) \ >+ dataLogLn("failed pass: " # pass); \ > return WTF::nullopt; \ >+ } \ > } while (0) > > >@@ -123,6 +129,7 @@ static Optional<Program> prepareShared(S > RUN_PASS(checkStatementBehavior, program); > RUN_PASS(checkRecursion, program); > RUN_PASS(checkFunctionStages, program); >+ preserveVariableLifetimes(program); > > dumpASTAtEndIfNeeded(program); > >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp (nonexistent) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp (working copy) >@@ -0,0 +1,319 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "WHLSLPreserveVariableLifetimes.h" >+ >+#if ENABLE(WEBGPU) >+ >+#include "WHLSLAST.h" >+#include "WHLSLASTDumper.h" >+#include "WHLSLVisitor.h" >+ >+namespace WebCore { >+ >+namespace WHLSL { >+ >+// This pass works by ensuring proper variable lifetimes. In WHLSL, each variable >+// has global lifetime. So returning a pointer to a local variable is a totally >+// legitimate and well specified thing to do. >+// >+// We implement this by: >+// - We note every variable whose address we take. >+// - Each such variable gets defined as a field in a struct. >+// - Each function which is an entry point defines this struct. >+// - Each non entry point takes a pointer to this struct as its final parameter. >+// - Each call is rewritten to pass a pointer to the struct as the last call argument. >+// - Each variable reference to "x", where "x" ends up in the struct, is >+// modified to instead be "struct->x". We store to "struct->x" after declaring >+// "x". If "x" is a function parameter, we store to "struct->x" as the first >+// thing we do in the function body. >+ >+class EscapedVariableCollector : public Visitor { >+ using Base = Visitor; >+public: >+ void visit(AST::MakePointerExpression& makePointerExpression) override >+ { >+ if (!is<AST::VariableReference>(makePointerExpression.leftValue())) { >+ // FIXME: Are we missing any interesting productions here? >+ // https://bugs.webkit.org/show_bug.cgi?id=198311 >+ Base::visit(makePointerExpression.leftValue()); >+ return; >+ } >+ >+ auto& variableReference = downcast<AST::VariableReference>(makePointerExpression.leftValue()); >+ auto* variable = variableReference.variable(); >+ // If variable is unnamed, it means it's internal. We don't allow internal variables to escape. >+ if (!variable->name().isEmpty()) >+ m_escapedVariables.add(variable, makeString("_", variable->name(), "_", m_count++)); >+ } >+ >+ HashMap<AST::VariableDeclaration*, String> takeEscapedVariables() { return WTFMove(m_escapedVariables); } >+ >+private: >+ size_t m_count { 1 }; >+ HashMap<AST::VariableDeclaration*, String> m_escapedVariables; >+}; >+ >+static ALWAYS_INLINE Lexer::Token anonymousToken(Lexer::Token::Type type) >+{ >+ return Lexer::Token { { }, 0, type }; >+} >+ >+class PreserveLifetimes : public Visitor { >+ using Base = Visitor; >+public: >+ PreserveLifetimes(UniqueRef<AST::TypeReference>& structType, const HashMap<AST::VariableDeclaration*, AST::StructureElement*>& variableMapping) >+ : m_structType(structType) >+ , m_pointerToStructType(makeUniqueRef<AST::PointerType>(anonymousToken(Lexer::Token::Type::Identifier), AST::AddressSpace::Thread, m_structType->clone())) >+ , m_variableMapping(variableMapping) >+ { } >+ >+ UniqueRef<AST::VariableReference> makeStructVariableReference() >+ { >+ auto structVariableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(*m_structVariable)); >+ structVariableReference->setType(m_structVariable->type()->clone()); >+ structVariableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); >+ return structVariableReference; >+ } >+ >+ void visit(AST::FunctionDefinition& functionDefinition) override >+ { >+ bool isEntryPoint = !!functionDefinition.entryPointType(); >+ if (isEntryPoint) { >+ auto structVariableDeclaration = makeUniqueRef<AST::VariableDeclaration>(functionDefinition.origin(), AST::Qualifiers(), >+ m_structType->clone(), String(), WTF::nullopt, WTF::nullopt); >+ >+ auto structVariableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(structVariableDeclaration)); >+ structVariableReference->setType(m_structType->clone()); >+ structVariableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); >+ >+ AST::VariableDeclarations structVariableDeclarations; >+ structVariableDeclarations.append(WTFMove(structVariableDeclaration)); >+ auto structDeclarationStatement = makeUniqueRef<AST::VariableDeclarationsStatement>(functionDefinition.origin(), WTFMove(structVariableDeclarations)); >+ >+ auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(functionDefinition.origin(), WTFMove(structVariableReference)); >+ makePointerExpression->setType(m_pointerToStructType->clone()); >+ makePointerExpression->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); >+ >+ auto pointerDeclaration = makeUniqueRef<AST::VariableDeclaration>(functionDefinition.origin(), AST::Qualifiers(), >+ m_pointerToStructType->clone(), "wrapper"_s, WTF::nullopt, Optional<UniqueRef<AST::Expression>>(WTFMove(makePointerExpression))); >+ m_structVariable = &pointerDeclaration; >+ >+ Base::visit(functionDefinition); >+ >+ AST::VariableDeclarations pointerVariableDeclarations; >+ pointerVariableDeclarations.append(WTFMove(pointerDeclaration)); >+ auto pointerDeclarationStatement = makeUniqueRef<AST::VariableDeclarationsStatement>(functionDefinition.origin(), WTFMove(pointerVariableDeclarations)); >+ >+ functionDefinition.block().statements().insert(0, WTFMove(structDeclarationStatement)); >+ functionDefinition.block().statements().insert(1, WTFMove(pointerDeclarationStatement)); >+ } else { >+ auto pointerDeclaration = makeUniqueRef<AST::VariableDeclaration>(functionDefinition.origin(), AST::Qualifiers(), >+ m_pointerToStructType->clone(), "wrapper"_s, WTF::nullopt, WTF::nullopt); >+ m_structVariable = &pointerDeclaration; >+ >+ Base::visit(functionDefinition); >+ >+ functionDefinition.parameters().append(WTFMove(pointerDeclaration)); >+ } >+ >+ for (auto& parameter : functionDefinition.parameters()) { >+ auto iter = m_variableMapping.find(¶meter); >+ if (iter == m_variableMapping.end()) >+ continue; >+ >+ auto structVariableReference = makeStructVariableReference(); >+ auto lhs = makeUniqueRef<AST::GlobalVariableReference>(parameter->origin(), WTFMove(structVariableReference), iter->value); >+ lhs->setType(parameter->type()->clone()); >+ lhs->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); >+ >+ auto rhs = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(parameter.get())); >+ rhs->setType(parameter->type()->clone()); >+ rhs->setTypeAnnotation(AST::RightValue()); >+ >+ auto assignment = makeUniqueRef<AST::AssignmentExpression>(parameter->origin(), WTFMove(lhs), WTFMove(rhs)); >+ assignment->setType(parameter->type()->clone()); >+ assignment->setTypeAnnotation(AST::RightValue()); >+ >+ functionDefinition.block().statements().insert(isEntryPoint ? 2 : 0, >+ makeUniqueRef<AST::EffectfulExpressionStatement>(WTFMove(assignment))); >+ } >+ >+ // Inner functions are not allowed in WHLSL. So this is fine. >+ m_structVariable = nullptr; >+ >+ for (UniqueRef<AST::VariableDeclaration>& variable : m_variablesToHoist) { >+ Lexer::Token origin = variable->origin(); >+ >+ AST::VariableDeclarations declarations; >+ ASSERT(!variable->initializer()); >+ declarations.append(WTFMove(variable)); >+ >+ functionDefinition.block().statements().insert(0, >+ makeUniqueRef<AST::VariableDeclarationsStatement>(WTFMove(origin), WTFMove(declarations))); >+ } >+ >+ m_variablesToHoist.clear(); >+ } >+ >+ void visit(AST::CallExpression& callExpression) override >+ { >+ RELEASE_ASSERT(m_structVariable); >+ >+ Base::visit(callExpression); >+ >+ // This works because it's illegal to call an entrypoint. Therefore, we can only >+ // call functions where we've already appended this struct as its final parameter. >+ if (!callExpression.function()->isNativeFunctionDeclaration()) >+ callExpression.arguments().append(makeStructVariableReference()); >+ } >+ >+ void visit(AST::VariableReference& variableReference) override >+ { >+ RELEASE_ASSERT(m_structVariable); >+ >+ auto iter = m_variableMapping.find(variableReference.variable()); >+ if (iter == m_variableMapping.end()) >+ return; >+ >+ auto type = variableReference.variable()->type()->clone(); >+ AST::TypeAnnotation typeAnnotation = variableReference.typeAnnotation(); >+ auto* internalField = AST::replaceWith<AST::GlobalVariableReference>(variableReference, variableReference.origin(), makeStructVariableReference(), iter->value); >+ internalField->setType(WTFMove(type)); >+ internalField->setTypeAnnotation(WTFMove(typeAnnotation)); >+ } >+ >+ void visit(AST::VariableDeclarationsStatement& variableDeclarationsStatement) override >+ { >+ RELEASE_ASSERT(m_structVariable); >+ >+ Base::visit(variableDeclarationsStatement); >+ >+ Vector<std::pair<AST::VariableDeclaration*, Optional<UniqueRef<AST::Expression>>>> variables; >+ for (UniqueRef<AST::VariableDeclaration>& variableDeclaration : variableDeclarationsStatement.variableDeclarations()) { >+ variables.append({ &variableDeclaration, variableDeclaration->takeInitializer() }); >+ m_variablesToHoist.append(WTFMove(variableDeclaration)); >+ } >+ >+ auto origin = Lexer::Token(variableDeclarationsStatement.origin()); >+ Vector<UniqueRef<AST::Expression>> expressions; >+ >+ for (auto& pair : variables) { >+ if (pair.second) { >+ auto lhs = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(*pair.first)); >+ lhs->setType(pair.first->type()->clone()); >+ lhs->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); >+ >+ auto rhs = WTFMove(pair.second.value()); >+ auto assignment = makeUniqueRef<AST::AssignmentExpression>(Lexer::Token(rhs->origin()), WTFMove(lhs), WTFMove(rhs)); >+ assignment->setType(pair.first->type()->clone()); >+ assignment->setTypeAnnotation(AST::RightValue()); >+ >+ expressions.append(WTFMove(assignment)); >+ } >+ >+ auto iter = m_variableMapping.find(pair.first); >+ if (iter != m_variableMapping.end()) { >+ auto lhs = makeUniqueRef<AST::GlobalVariableReference>(Lexer::Token(origin), makeStructVariableReference(), iter->value); >+ lhs->setType(pair.first->type()->clone()); >+ lhs->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); >+ >+ auto rhs = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(*pair.first)); >+ rhs->setType(pair.first->type()->clone()); >+ rhs->setTypeAnnotation(AST::RightValue()); >+ >+ auto assignment = makeUniqueRef<AST::AssignmentExpression>(Lexer::Token(origin), WTFMove(lhs), WTFMove(rhs)); >+ assignment->setType(pair.first->type()->clone()); >+ assignment->setTypeAnnotation(AST::RightValue()); >+ >+ expressions.append(WTFMove(assignment)); >+ } >+ } >+ >+ auto dummyResult = makeStructVariableReference(); >+ auto dummyResultType = dummyResult->resolvedType().clone(); >+ expressions.append(WTFMove(dummyResult)); >+ >+ auto comma = makeUniqueRef<AST::CommaExpression>(Lexer::Token(origin), WTFMove(expressions)); >+ comma->setType(WTFMove(dummyResultType)); >+ comma->setTypeAnnotation(AST::RightValue()); >+ >+ AST::replaceWith<AST::EffectfulExpressionStatement>(variableDeclarationsStatement, WTFMove(comma)); >+ } >+ >+private: >+ AST::VariableDeclaration* m_structVariable { nullptr }; >+ >+ UniqueRef<AST::TypeReference>& m_structType; >+ UniqueRef<AST::PointerType> m_pointerToStructType; >+ const HashMap<AST::VariableDeclaration*, AST::StructureElement*>& m_variableMapping; >+ Vector<UniqueRef<AST::VariableDeclaration>> m_variablesToHoist; >+}; >+ >+void preserveVariableLifetimes(Program& program) >+{ >+ HashMap<AST::VariableDeclaration*, String> escapedVariables; >+ { >+ EscapedVariableCollector collector; >+ collector.Visitor::visit(program); >+ escapedVariables = collector.takeEscapedVariables(); >+ } >+ >+ AST::StructureElements elements; >+ for (auto& pair : escapedVariables) { >+ auto* variable = pair.key; >+ String name = pair.value; >+ elements.append(AST::StructureElement { Lexer::Token(variable->origin()), { }, variable->type()->clone(), WTFMove(name), WTF::nullopt }); >+ } >+ >+ // Name of this doesn't matter, since we don't use struct names when >+ // generating Metal type names. We just pick something here to make it >+ // easy to read in AST dumps. >+ String structName = "__WrapperStruct__"_s; >+ >+ auto wrapperStruct = makeUniqueRef<AST::StructureDefinition>(anonymousToken(Lexer::Token::Type::Struct), String(structName), WTFMove(elements)); >+ >+ HashMap<AST::VariableDeclaration*, AST::StructureElement*> variableMapping; >+ unsigned index = 0; >+ for (auto& pair : escapedVariables) >+ variableMapping.add(pair.key, &wrapperStruct->structureElements()[index++]); >+ >+ auto structType = makeUniqueRef<AST::TypeReference>(anonymousToken(Lexer::Token::Type::Identifier), String(structName), AST::TypeArguments()); >+ structType->setResolvedType(wrapperStruct.get()); >+ >+ { >+ PreserveLifetimes preserveLifetimes(structType, variableMapping); >+ preserveLifetimes.Visitor::visit(program); >+ } >+ >+ program.structureDefinitions().append(WTFMove(wrapperStruct)); >+} >+ >+} // namespace WHLSL >+ >+} // namespace WebCore >+ >+#endif // ENABLE(WEBGPU) >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.h (nonexistent) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.h (working copy) >@@ -0,0 +1,42 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#if ENABLE(WEBGPU) >+ >+namespace WebCore { >+ >+namespace WHLSL { >+ >+class Program; >+ >+void preserveVariableLifetimes(Program&); >+ >+} >+ >+} >+ >+#endif >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLVisitor.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLVisitor.cpp (revision 245881) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLVisitor.cpp (working copy) >@@ -376,6 +376,8 @@ void Visitor::visit(AST::Expression& exp > checkErrorAndVisit(downcast<AST::NullLiteral>(expression)); > else if (is<AST::DotExpression>(expression)) > checkErrorAndVisit(downcast<AST::DotExpression>(expression)); >+ else if (is<AST::GlobalVariableReference>(expression)) >+ checkErrorAndVisit(downcast<AST::GlobalVariableReference>(expression)); > else if (is<AST::IndexExpression>(expression)) > checkErrorAndVisit(downcast<AST::IndexExpression>(expression)); > else if (is<AST::ReadModifyWriteExpression>(expression)) >@@ -397,6 +399,11 @@ void Visitor::visit(AST::DotExpression& > checkErrorAndVisit(static_cast<AST::PropertyAccessExpression&>(dotExpression)); > } > >+void Visitor::visit(AST::GlobalVariableReference& globalVariableReference) >+{ >+ checkErrorAndVisit(globalVariableReference.base()); >+} >+ > void Visitor::visit(AST::IndexExpression& indexExpression) > { > checkErrorAndVisit(indexExpression.indexExpression()); >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLVisitor.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLVisitor.h (revision 245881) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLVisitor.h (working copy) >@@ -72,6 +72,7 @@ class Continue; > class DoWhileLoop; > class Expression; > class DotExpression; >+class GlobalVariableReference; > class IndexExpression; > class PropertyAccessExpression; > class EffectfulExpressionStatement; >@@ -151,6 +152,7 @@ public: > virtual void visit(AST::DoWhileLoop&); > virtual void visit(AST::Expression&); > virtual void visit(AST::DotExpression&); >+ virtual void visit(AST::GlobalVariableReference&); > virtual void visit(AST::IndexExpression&); > virtual void visit(AST::PropertyAccessExpression&); > virtual void visit(AST::EffectfulExpressionStatement&); >Index: Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLAST.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLAST.h (revision 245881) >+++ Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLAST.h (working copy) >@@ -57,6 +57,7 @@ > #include "WHLSLFunctionAttribute.h" > #include "WHLSLFunctionDeclaration.h" > #include "WHLSLFunctionDefinition.h" >+#include "WHLSLGlobalVariableReference.h" > #include "WHLSLIfStatement.h" > #include "WHLSLIndexExpression.h" > #include "WHLSLIntegerLiteral.h" >Index: Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLExpression.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLExpression.h (revision 245881) >+++ Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLExpression.h (working copy) >@@ -41,9 +41,10 @@ namespace WHLSL { > namespace AST { > > class Expression : public Value { >+ using Base = Value; > public: > Expression(Lexer::Token&& origin) >- : m_origin(WTFMove(origin)) >+ : Base(WTFMove(origin)) > { > } > >@@ -55,8 +56,6 @@ public: > Expression& operator=(const Expression&) = delete; > Expression& operator=(Expression&&) = default; > >- const Lexer::Token& origin() const { return m_origin; } >- > UnnamedType* maybeResolvedType() { return m_type ? &*m_type : nullptr; } > > UnnamedType& resolvedType() >@@ -91,6 +90,7 @@ public: > virtual bool isCommaExpression() const { return false; } > virtual bool isDereferenceExpression() const { return false; } > virtual bool isDotExpression() const { return false; } >+ virtual bool isGlobalVariableReference() const { return false; } > virtual bool isFloatLiteral() const { return false; } > virtual bool isIndexExpression() const { return false; } > virtual bool isIntegerLiteral() const { return false; } >@@ -107,7 +107,6 @@ public: > virtual bool isEnumerationMemberLiteral() const { return false; } > > private: >- Lexer::Token m_origin; > Optional<UniqueRef<UnnamedType>> m_type; > Optional<TypeAnnotation> m_typeAnnotation; > }; >Index: Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLFunctionDeclaration.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLFunctionDeclaration.h (revision 245881) >+++ Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLFunctionDeclaration.h (working copy) >@@ -76,6 +76,7 @@ public: > VariableDeclarations& parameters() { return m_parameters; } > Optional<Semantic>& semantic() { return m_semantic; } > bool isOperator() const { return m_isOperator; } >+ Lexer::Token origin() { return m_origin; } > > private: > Lexer::Token m_origin; >Index: Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLGlobalVariableReference.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLGlobalVariableReference.h (nonexistent) >+++ Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLGlobalVariableReference.h (working copy) >@@ -0,0 +1,69 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#if ENABLE(WEBGPU) >+ >+#include "WHLSLLexer.h" >+#include "WHLSLStructureElement.h" >+#include <wtf/UniqueRef.h> >+ >+namespace WebCore { >+ >+namespace WHLSL { >+ >+namespace AST { >+ >+class GlobalVariableReference : public Expression { >+public: >+ GlobalVariableReference(Lexer::Token&& origin, UniqueRef<Expression>&& base, StructureElement* structField) >+ : Expression(WTFMove(origin)) >+ , m_base(WTFMove(base)) >+ , m_structField(*structField) >+ { >+ ASSERT(structField); >+ } >+ >+ virtual ~GlobalVariableReference() = default; >+ bool isGlobalVariableReference() const override { return true; } >+ StructureElement& structField() { return m_structField; } >+ >+ Expression& base() { return m_base.get(); } >+ >+private: >+ UniqueRef<Expression> m_base; >+ StructureElement& m_structField; >+}; >+ >+} // namespace AST >+ >+} >+ >+} >+ >+SPECIALIZE_TYPE_TRAITS_WHLSL_EXPRESSION(GlobalVariableReference, isGlobalVariableReference()) >+ >+#endif >Index: Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLStatement.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLStatement.h (revision 245881) >+++ Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLStatement.h (working copy) >@@ -38,9 +38,10 @@ namespace WHLSL { > namespace AST { > > class Statement : public Value { >+ using Base = Value; > public: > Statement(Lexer::Token&& origin) >- : m_origin(WTFMove(origin)) >+ : Base(WTFMove(origin)) > { > } > >@@ -63,9 +64,6 @@ public: > virtual bool isTrap() const { return false; } > virtual bool isVariableDeclarationsStatement() const { return false; } > virtual bool isWhileLoop() const { return false; } >- >-private: >- Lexer::Token m_origin; > }; > > using Statements = Vector<UniqueRef<Statement>>; >Index: Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLValue.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLValue.h (revision 245881) >+++ Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLValue.h (working copy) >@@ -37,7 +37,8 @@ namespace AST { > > class Value : public Node { > public: >- Value() >+ Value(Lexer::Token&& origin) >+ : m_origin(WTFMove(origin)) > { > } > >@@ -49,7 +50,10 @@ public: > Value& operator=(const Value&) = default; > Value& operator=(Value&&) = default; > >-private: >+ Lexer::Token origin() const { return m_origin; } >+ >+protected: >+ Lexer::Token m_origin; > }; > > } // namespace AST >Index: Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLVariableDeclaration.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLVariableDeclaration.h (revision 245881) >+++ Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLVariableDeclaration.h (working copy) >@@ -45,9 +45,10 @@ namespace WHLSL { > namespace AST { > > class VariableDeclaration : public Value { >+ using Base = Value; > public: > VariableDeclaration(Lexer::Token&& origin, Qualifiers&& qualifiers, Optional<UniqueRef<UnnamedType>>&& type, String&& name, Optional<Semantic>&& semantic, Optional<UniqueRef<Expression>>&& initializer) >- : m_origin(WTFMove(origin)) >+ : Base(WTFMove(origin)) > , m_qualifiers(WTFMove(qualifiers)) > , m_type(WTFMove(type)) > , m_name(WTFMove(name)) >@@ -61,7 +62,6 @@ public: > VariableDeclaration(const VariableDeclaration&) = delete; > VariableDeclaration(VariableDeclaration&&) = default; > >- const Lexer::Token& origin() const { return m_origin; } > String& name() { return m_name; } > > const Optional<UniqueRef<UnnamedType>>& type() const { return m_type; } // Anonymous variables inside ReadModifyWriteExpressions have their type set by the type checker. >@@ -69,9 +69,9 @@ public: > Optional<Semantic>& semantic() { return m_semantic; } > Expression* initializer() { return m_initializer ? &*m_initializer : nullptr; } > bool isAnonymous() const { return m_name.isNull(); } >+ Optional<UniqueRef<Expression>> takeInitializer() { return WTFMove(m_initializer); } > > private: >- Lexer::Token m_origin; > Qualifiers m_qualifiers; > Optional<UniqueRef<UnnamedType>> m_type; > String m_name; >Index: Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLVariableReference.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLVariableReference.h (revision 245881) >+++ Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLVariableReference.h (working copy) >@@ -55,6 +55,7 @@ public: > { > VariableReference result(Lexer::Token(variableDeclaration.origin())); > result.m_variable = &variableDeclaration; >+ result.m_name = variableDeclaration.name(); > return result; > } > >Index: Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp (revision 245881) >+++ Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp (working copy) >@@ -29,44 +29,11 @@ > #if ENABLE(WEBGPU) > > #include "NotImplemented.h" >-#include "WHLSLArrayReferenceType.h" >-#include "WHLSLArrayType.h" >-#include "WHLSLAssignmentExpression.h" >-#include "WHLSLBooleanLiteral.h" >-#include "WHLSLBuiltInSemantic.h" >-#include "WHLSLCallExpression.h" >-#include "WHLSLCommaExpression.h" >-#include "WHLSLDereferenceExpression.h" >-#include "WHLSLDoWhileLoop.h" >-#include "WHLSLEffectfulExpressionStatement.h" >-#include "WHLSLEntryPointScaffolding.h" >-#include "WHLSLEntryPointType.h" >-#include "WHLSLFloatLiteral.h" >-#include "WHLSLForLoop.h" >-#include "WHLSLFunctionDeclaration.h" >-#include "WHLSLFunctionDefinition.h" >-#include "WHLSLIfStatement.h" >-#include "WHLSLIntegerLiteral.h" >-#include "WHLSLLogicalExpression.h" >-#include "WHLSLLogicalNotExpression.h" >-#include "WHLSLMakeArrayReferenceExpression.h" >-#include "WHLSLMakePointerExpression.h" >-#include "WHLSLNativeFunctionDeclaration.h" >+#include "WHLSLAST.h" > #include "WHLSLNativeFunctionWriter.h" >-#include "WHLSLNativeTypeDeclaration.h" >-#include "WHLSLPointerType.h" > #include "WHLSLProgram.h" >-#include "WHLSLReturn.h" >-#include "WHLSLSwitchCase.h" >-#include "WHLSLSwitchStatement.h" >-#include "WHLSLTernaryExpression.h" > #include "WHLSLTypeNamer.h" >-#include "WHLSLUnsignedIntegerLiteral.h" >-#include "WHLSLVariableDeclaration.h" >-#include "WHLSLVariableDeclarationsStatement.h" >-#include "WHLSLVariableReference.h" > #include "WHLSLVisitor.h" >-#include "WHLSLWhileLoop.h" > #include <wtf/HashMap.h> > #include <wtf/text/StringBuilder.h> > >@@ -156,6 +123,7 @@ protected: > void visit(AST::EnumerationMemberLiteral&) override; > void visit(AST::Expression&) override; > void visit(AST::DotExpression&) override; >+ void visit(AST::GlobalVariableReference&) override; > void visit(AST::IndexExpression&) override; > void visit(AST::PropertyAccessExpression&) override; > void visit(AST::VariableDeclaration&) override; >@@ -446,6 +414,15 @@ void FunctionDefinitionWriter::visit(AST > m_stack.append("dummy"); > } > >+void FunctionDefinitionWriter::visit(AST::GlobalVariableReference& globalVariableReference) >+{ >+ auto variableName = 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); >+} >+ > void FunctionDefinitionWriter::visit(AST::IndexExpression&) > { > // This should be lowered already. >Index: Source/WebCore/WebCore.xcodeproj/project.pbxproj >=================================================================== >--- Source/WebCore/WebCore.xcodeproj/project.pbxproj (revision 245830) >+++ Source/WebCore/WebCore.xcodeproj/project.pbxproj (working copy) >@@ -8334,6 +8334,9 @@ > 51FB67DA1AE6B5E400D06C5A /* ContentExtensionStyleSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContentExtensionStyleSheet.h; sourceTree = "<group>"; }; > 52131E5A1C4F15610033F802 /* VideoFullscreenInterfaceMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = VideoFullscreenInterfaceMac.mm; sourceTree = "<group>"; }; > 5215862C229377B7005925EF /* WHLSLAST.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLAST.h; sourceTree = "<group>"; }; >+ 522DA3D3229E1D390042D151 /* WHLSLGlobalVariableReference.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLGlobalVariableReference.h; sourceTree = "<group>"; }; >+ 522E1A172297D6D400E5D36A /* WHLSLPreserveVariableLifetimes.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WHLSLPreserveVariableLifetimes.cpp; sourceTree = "<group>"; }; >+ 522E1A192297D6D400E5D36A /* WHLSLPreserveVariableLifetimes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLPreserveVariableLifetimes.h; sourceTree = "<group>"; }; > 526724F11CB2FDF60075974D /* TextTrackRepresentationCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TextTrackRepresentationCocoa.mm; sourceTree = "<group>"; }; > 526724F21CB2FDF60075974D /* TextTrackRepresentationCocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextTrackRepresentationCocoa.h; sourceTree = "<group>"; }; > 52B0D4BD1C57FD1E0077CE53 /* PlatformView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformView.h; sourceTree = "<group>"; }; >@@ -17062,6 +17065,7 @@ > C21BF70521CD89C700227979 /* WHLSLFunctionAttribute.h */, > C21BF6FD21CD89C000227979 /* WHLSLFunctionDeclaration.h */, > C21BF6F421CD89B300227979 /* WHLSLFunctionDefinition.h */, >+ 522DA3D3229E1D390042D151 /* WHLSLGlobalVariableReference.h */, > C21BF6FF21CD89C200227979 /* WHLSLIfStatement.h */, > C21BF6F721CD89B900227979 /* WHLSLIndexExpression.h */, > C20F4F6621DFF2360070C45A /* WHLSLIntegerLiteral.cpp */, >@@ -25448,6 +25452,8 @@ > C24A57AF21FAD53F004C6DD1 /* WHLSLPipelineDescriptor.h */, > C24A57BA21FEAFEA004C6DD1 /* WHLSLPrepare.cpp */, > C24A57BB21FEAFEA004C6DD1 /* WHLSLPrepare.h */, >+ 522E1A172297D6D400E5D36A /* WHLSLPreserveVariableLifetimes.cpp */, >+ 522E1A192297D6D400E5D36A /* WHLSLPreserveVariableLifetimes.h */, > C21BF73A21CD8D7000227979 /* WHLSLProgram.h */, > 1CAA82F62242AE0500E84BBB /* WHLSLPropertyResolver.cpp */, > 1CAA82F72242AE0500E84BBB /* WHLSLPropertyResolver.h */, >Index: LayoutTests/ChangeLog >=================================================================== >--- LayoutTests/ChangeLog (revision 245881) >+++ LayoutTests/ChangeLog (working copy) >@@ -1,3 +1,16 @@ >+2019-05-29 Saam Barati <sbarati@apple.com> >+ >+ [WHLSL] Enforce variable lifetimes >+ https://bugs.webkit.org/show_bug.cgi?id=195794 >+ <rdar://problem/50746293> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * webgpu/whlsl-ensure-proper-variable-lifetime-2-expected.html: Added. >+ * webgpu/whlsl-ensure-proper-variable-lifetime-2.html: Added. >+ * webgpu/whlsl-ensure-proper-variable-lifetime-expected.html: Added. >+ * webgpu/whlsl-ensure-proper-variable-lifetime.html: Added. >+ > 2019-05-29 Said Abou-Hallawa <sabouhallawa@apple.com> > > REGRESSION (r244182) [Mac WK2] Layout Test imported/w3c/web-platform-tests/visual-viewport/viewport-resize-event-on-load-overflowing-page.html is a flaky failure >Index: LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-2-expected.html >=================================================================== >--- LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-2-expected.html (nonexistent) >+++ LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-2-expected.html (working copy) >@@ -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> >Index: LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-2.html >=================================================================== >--- LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-2.html (nonexistent) >+++ LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-2.html (working copy) >@@ -0,0 +1,153 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+const shaderSource = ` >+struct VertexOut { >+ float4 position : SV_Position; >+ float shade : attribute(0); >+} >+ >+float assignToPtr(thread float* ptr, float value) { >+ return *ptr = value; >+} >+ >+thread float* realPtr(float value) >+{ >+ return &value; >+} >+ >+thread float* firstPtr(float value) { >+ return realPtr(value); >+} >+ >+thread float* secondPtr(float value) { >+ return firstPtr(value); >+} >+ >+vertex VertexOut vertexShader(float4 position : attribute(0), float shade : attribute(1)) { >+ VertexOut result; >+ >+ thread float* ptrToShade = firstPtr(shade); >+ thread float* ptrToShade2 = secondPtr(1.0); >+ >+ float dummy; >+ thread float* dummyPtr = &dummy; >+ >+ dummy = assignToPtr(ptrToShade2, 0.0); >+ thread float* dummy2 = realPtr(shade); >+ >+ result.position = position; >+ >+ result.shade = *ptrToShade2; >+ >+ return result; >+} >+ >+fragment float4 fragmentShader(float shade : attribute(0)) : SV_Target 0 { >+ return float4(shade, shade, shade, 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, inputSlot: 0, format: "float4", offset: 0}; >+ const attribute1 = {shaderLocation: 1, inputSlot: 0, format: "float", offset: 16}; >+ const attributes = [attribute0, attribute1]; >+ const input0 = {inputSlot: 0, stride: 20 }; >+ const inputs = [input0]; >+ const inputState = {indexFormat: "uint32", attributes, inputs}; >+ >+ const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "uniform-buffer"}]}; >+ const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor); >+ const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, inputState, sampleCount: 1, layout: pipelineLayout}; >+ const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor); >+ >+ const vertexBuffer0Descriptor = {size: Float32Array.BYTES_PER_ELEMENT * 5 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE}; >+ const vertexBuffer0 = device.createBuffer(vertexBuffer0Descriptor); >+ const vertexBuffer0ArrayBuffer = await vertexBuffer0.mapWriteAsync(); >+ const vertexBuffer0Float32Array = new Float32Array(vertexBuffer0ArrayBuffer); >+ vertexBuffer0Float32Array[0] = -0.5; >+ vertexBuffer0Float32Array[1] = -0.5; >+ vertexBuffer0Float32Array[2] = 1.0; >+ vertexBuffer0Float32Array[3] = 1.0; >+ vertexBuffer0Float32Array[4] = 1.0; >+ >+ vertexBuffer0Float32Array[5] = -0.5; >+ vertexBuffer0Float32Array[6] = 0.5; >+ vertexBuffer0Float32Array[7] = 1.0; >+ vertexBuffer0Float32Array[8] = 1.0; >+ vertexBuffer0Float32Array[9] = 1.0; >+ >+ vertexBuffer0Float32Array[10] = 0.5; >+ vertexBuffer0Float32Array[11] = -0.5; >+ vertexBuffer0Float32Array[12] = 1.0; >+ vertexBuffer0Float32Array[13] = 1.0; >+ vertexBuffer0Float32Array[14] = 1.0; >+ >+ vertexBuffer0Float32Array[15] = 0.5; >+ vertexBuffer0Float32Array[16] = 0.5; >+ vertexBuffer0Float32Array[17] = 1.0; >+ vertexBuffer0Float32Array[18] = 1.0; >+ vertexBuffer0Float32Array[19] = 1.0; >+ vertexBuffer0.unmap(); >+ >+ const resourceBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE}; >+ const resourceBuffer = device.createBuffer(resourceBufferDescriptor); >+ const resourceBufferArrayBuffer = await resourceBuffer.mapWriteAsync(); >+ const resourceBufferFloat32Array = new Float32Array(resourceBufferArrayBuffer); >+ resourceBufferFloat32Array[0] = 1; >+ resourceBuffer.unmap(); >+ >+ const bufferBinding = {buffer: resourceBuffer, size: 4}; >+ const bindGroupBinding = {binding: 0, resource: bufferBinding}; >+ const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]}; >+ const bindGroup = device.createBindGroup(bindGroupDescriptor); >+ >+ 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.setBindGroup(0, bindGroup); >+ renderPassEncoder.setVertexBuffers(0, [vertexBuffer0], [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> >Index: LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-expected.html >=================================================================== >--- LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-expected.html (nonexistent) >+++ LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-expected.html (working copy) >@@ -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> >Index: LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime.html >=================================================================== >--- LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime.html (nonexistent) >+++ LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime.html (working copy) >@@ -0,0 +1,153 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+const shaderSource = ` >+struct VertexOut { >+ float4 position : SV_Position; >+ float shade : attribute(0); >+} >+ >+float assignToPtr(thread float* ptr, float value) { >+ return *ptr = value; >+} >+ >+thread float* realPtr(float value) >+{ >+ return &value; >+} >+ >+thread float* firstPtr(float value) { >+ return realPtr(value); >+} >+ >+thread float* secondPtr(float value) { >+ return firstPtr(value); >+} >+ >+vertex VertexOut vertexShader(float4 position : attribute(0), float shade : attribute(1)) { >+ VertexOut result; >+ >+ thread float* ptrToShade = firstPtr(shade); >+ thread float* ptrToShade2 = secondPtr(1.0); >+ >+ float dummy; >+ thread float* dummyPtr = &dummy; >+ >+ dummy = assignToPtr(ptrToShade2, 0.0); >+ dummy = assignToPtr(ptrToShade, shade); >+ >+ result.position = position; >+ >+ result.shade = *ptrToShade2; >+ >+ return result; >+} >+ >+fragment float4 fragmentShader(float shade : attribute(0)) : SV_Target 0 { >+ return float4(shade, shade, shade, 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, inputSlot: 0, format: "float4", offset: 0}; >+ const attribute1 = {shaderLocation: 1, inputSlot: 0, format: "float", offset: 16}; >+ const attributes = [attribute0, attribute1]; >+ const input0 = {inputSlot: 0, stride: 20 }; >+ const inputs = [input0]; >+ const inputState = {indexFormat: "uint32", attributes, inputs}; >+ >+ const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "uniform-buffer"}]}; >+ const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor); >+ const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, inputState, sampleCount: 1, layout: pipelineLayout}; >+ const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor); >+ >+ const vertexBuffer0Descriptor = {size: Float32Array.BYTES_PER_ELEMENT * 5 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE}; >+ const vertexBuffer0 = device.createBuffer(vertexBuffer0Descriptor); >+ const vertexBuffer0ArrayBuffer = await vertexBuffer0.mapWriteAsync(); >+ const vertexBuffer0Float32Array = new Float32Array(vertexBuffer0ArrayBuffer); >+ vertexBuffer0Float32Array[0] = -0.5; >+ vertexBuffer0Float32Array[1] = -0.5; >+ vertexBuffer0Float32Array[2] = 1.0; >+ vertexBuffer0Float32Array[3] = 1.0; >+ vertexBuffer0Float32Array[4] = 1.0; >+ >+ vertexBuffer0Float32Array[5] = -0.5; >+ vertexBuffer0Float32Array[6] = 0.5; >+ vertexBuffer0Float32Array[7] = 1.0; >+ vertexBuffer0Float32Array[8] = 1.0; >+ vertexBuffer0Float32Array[9] = 1.0; >+ >+ vertexBuffer0Float32Array[10] = 0.5; >+ vertexBuffer0Float32Array[11] = -0.5; >+ vertexBuffer0Float32Array[12] = 1.0; >+ vertexBuffer0Float32Array[13] = 1.0; >+ vertexBuffer0Float32Array[14] = 1.0; >+ >+ vertexBuffer0Float32Array[15] = 0.5; >+ vertexBuffer0Float32Array[16] = 0.5; >+ vertexBuffer0Float32Array[17] = 1.0; >+ vertexBuffer0Float32Array[18] = 1.0; >+ vertexBuffer0Float32Array[19] = 1.0; >+ vertexBuffer0.unmap(); >+ >+ const resourceBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE}; >+ const resourceBuffer = device.createBuffer(resourceBufferDescriptor); >+ const resourceBufferArrayBuffer = await resourceBuffer.mapWriteAsync(); >+ const resourceBufferFloat32Array = new Float32Array(resourceBufferArrayBuffer); >+ resourceBufferFloat32Array[0] = 1; >+ resourceBuffer.unmap(); >+ >+ const bufferBinding = {buffer: resourceBuffer, size: 4}; >+ const bindGroupBinding = {binding: 0, resource: bufferBinding}; >+ const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]}; >+ const bindGroup = device.createBindGroup(bindGroupDescriptor); >+ >+ 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.setBindGroup(0, bindGroup); >+ renderPassEncoder.setVertexBuffers(0, [vertexBuffer0], [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:
mmaxfield
:
review+
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 195794
:
370539
|
370620
|
370786
|
370795
|
370802
|
370821
|
370827
|
370915
|
370916
|
370959
|
370999
|
371004
|
371027