WebKit Bugzilla
Attachment 373457 Details for
Bug 199289
: [WHLSL] 'uint y = x ? 1 : 2' fails to typecheck
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
patch
b-backup.diff (text/plain), 38.41 KB, created by
Saam Barati
on 2019-07-04 01:32:39 PDT
(
hide
)
Description:
patch
Filename:
MIME Type:
Creator:
Saam Barati
Created:
2019-07-04 01:32:39 PDT
Size:
38.41 KB
patch
obsolete
>Index: Source/WebCore/ChangeLog >=================================================================== >--- Source/WebCore/ChangeLog (revision 247135) >+++ Source/WebCore/ChangeLog (working copy) >@@ -1,3 +1,78 @@ >+2019-07-04 Saam Barati <sbarati@apple.com> >+ >+ [WHLSL] 'uint y = x ? 1 : 2' fails to typecheck >+ https://bugs.webkit.org/show_bug.cgi?id=199289 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ The main issue with the prior code is that ResolvableTypeReference was >+ only one level deep. So if we ever merged two ResolvableTypeReferences, >+ we would just commit them to their default values. So when we had code >+ like "(b ? 1 : 2)", the ternary expressions type would get committed >+ to int before we had a chance to allow it to match another type. So this >+ program would incorrectly fail to type check: >+ "float f = b ? 1 : 2;" >+ >+ The solution is to defer committing to a concrete type until as late as >+ possible. As late as possible usually means once we are asked to match a >+ specific type. For example, in variable assignment. >+ >+ ResolvableTypeReference now forms a tree data structure, where we use the tree >+ to build up these ResolvableTypeReferences. Once asked to commit a ResolvableTypeReference >+ to a specific type, we commit the entire tree in one go (or fail to do so). >+ >+ However, some statements in the language will never cause us to commit >+ to a specific type. For example: >+ "(b ? 20.0 : 30);" >+ >+ In such a scenario, the Checker must choose an appropriate type for >+ the entire tree. If anything in the tree is composed of null, we fail >+ to type check. Otherwise, the precedence we choose is: >+ 1. float >+ 2. int >+ 3. uint >+ >+ When we assignTypes() at the end of type checking, we will encounter some >+ ResolvableTypeReference trees with no committed type. When we encounter >+ any such tree, we always start with the root of the tree when choosing the >+ type given the above precedence rules. This is because the root of the >+ tree is the only node in the tree that is able to analyze each leaf and >+ evaluate the above precedence. If we didn't do this, we'd be beholden to >+ committing to types of various subtrees in the order we happen to walk >+ a pointer based hash table (which is essentially random for each program >+ invocation). Unfortunately, a lot of the complexity in this patch comes >+ from supporting this behavior in a well defined manner, which ultimately >+ only serves the purpose of supporting anonymous ternary expressions over >+ a tree of literals. >+ >+ Tests: webgpu/whlsl-nested-resolvable-types.html >+ webgpu/whlsl-resolvable-types-should-fail.html >+ >+ * Modules/webgpu/WHLSL/WHLSLChecker.cpp: >+ (WebCore::WHLSL::resolveByInstantiation): >+ (WebCore::WHLSL::matchAndCommit): >+ (WebCore::WHLSL::commitIfNeeded): >+ (WebCore::WHLSL::Checker::assignTypes): >+ (WebCore::WHLSL::commit): >+ (WebCore::WHLSL::Checker::assignType): >+ (WebCore::WHLSL::Checker::visit): >+ (WebCore::WHLSL::getUnnamedType): >+ (WebCore::WHLSL::Checker::isBoolType): >+ * Modules/webgpu/WHLSL/WHLSLInferTypes.cpp: >+ (WebCore::WHLSL::inferTypesForCallImpl): >+ * Modules/webgpu/WHLSL/WHLSLParser.cpp: >+ (WebCore::WHLSL::Parser::parseConstantExpression): >+ * Modules/webgpu/WHLSL/WHLSLPrepare.cpp: >+ * Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.cpp: >+ (WebCore::WHLSL::conversionCost): >+ * Modules/webgpu/WHLSL/WHLSLResolvingType.h: >+ (WebCore::WHLSL::ResolvableTypeReference::ResolvableTypeReference): >+ (WebCore::WHLSL::ResolvableTypeReference::forEachType): >+ (WebCore::WHLSL::ResolvableTypeReference::setParent): >+ (WebCore::WHLSL::ResolvableTypeReference::root): >+ (WebCore::WHLSL::ResolvableTypeReference::resolvableType): Deleted. >+ (WebCore::WHLSL::ResolvingType::operator=): Deleted. >+ > 2019-07-03 Eric Carlson <eric.carlson@apple.com> > > [MSE] Add more debug and error logging >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp (revision 247086) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp (working copy) >@@ -177,7 +177,11 @@ static Optional<AST::NativeFunctionDecla > bool secondArgumentIsUint = types[1].get().visit(WTF::makeVisitor([&](UniqueRef<AST::UnnamedType>& unnamedType) -> bool { > return matches(unnamedType, intrinsics.uintType()); > }, [&](RefPtr<ResolvableTypeReference>& resolvableTypeReference) -> bool { >- return resolvableTypeReference->resolvableType().canResolve(intrinsics.uintType()); >+ bool ok = true; >+ resolvableTypeReference->forEachType([&] (AST::ResolvableType& type) { >+ ok &= type.canResolve(intrinsics.uintType()); >+ }); >+ return ok; > })); > if (firstArgumentArrayRef && secondArgumentIsUint) > return resolveWithOperatorAnderIndexer(origin, *firstArgumentArrayRef, intrinsics); >@@ -196,7 +200,11 @@ static Optional<AST::NativeFunctionDecla > return resolvingType.visit(WTF::makeVisitor([](UniqueRef<AST::UnnamedType>& unnamedType) -> Acceptability { > return is<AST::ReferenceType>(static_cast<AST::UnnamedType&>(unnamedType)) ? Acceptability::Yes : Acceptability::No; > }, [](RefPtr<ResolvableTypeReference>& resolvableTypeReference) -> Acceptability { >- return is<AST::NullLiteralType>(resolvableTypeReference->resolvableType()) ? Acceptability::Maybe : Acceptability::No; >+ bool allAreNull = true; >+ resolvableTypeReference->forEachType([&] (AST::ResolvableType& type) { >+ allAreNull &= is<AST::NullLiteralType>(type); >+ }); >+ return allAreNull ? Acceptability::Maybe : Acceptability::No; > })); > }; > auto leftAcceptability = acceptability(types[0].get()); >@@ -469,8 +477,9 @@ private: > Optional<RecurseInfo> getInfo(AST::Expression&, bool requiresLeftValue = false); > Optional<UniqueRef<AST::UnnamedType>> recurseAndWrapBaseType(AST::PropertyAccessExpression&); > bool recurseAndRequireBoolType(AST::Expression&); >- void assignType(AST::Expression&, UniqueRef<AST::UnnamedType>&&, AST::TypeAnnotation); >- void assignType(AST::Expression&, RefPtr<ResolvableTypeReference>&&, AST::TypeAnnotation); >+ void assignType(AST::Expression&, UniqueRef<AST::UnnamedType>&&, AST::TypeAnnotation = AST::RightValue()); >+ void assignType(AST::Expression&, RefPtr<ResolvableTypeReference>&&, AST::TypeAnnotation = AST::RightValue()); >+ void assignType(AST::Expression&, ResolvingType, AST::TypeAnnotation = AST::RightValue()); > void forwardType(AST::Expression&, ResolvingType&, AST::TypeAnnotation); > > void visit(AST::FunctionDefinition&) override; >@@ -534,6 +543,91 @@ void Checker::visit(Program& program) > checkErrorAndVisit(program.nativeFunctionDeclarations()[i]); > } > >+template <typename Type> >+static Optional<UniqueRef<AST::UnnamedType>> matchAndCommit(const RefPtr<ResolvableTypeReference>& resolvableTypeReference, Type& matchingType) >+{ >+ static_assert(std::is_same<Type, AST::NamedType>::value || std::is_same<Type, AST::UnnamedType>::value, ""); >+ Optional<UniqueRef<AST::UnnamedType>> result; >+ bool ok = true; >+ resolvableTypeReference->forEachType([&] (AST::ResolvableType& type) { >+ result = matchAndCommit(matchingType, type); >+ ok &= !!result; >+ }); >+ return ok ? WTFMove(result) : WTF::nullopt; >+} >+ >+static Optional<UniqueRef<AST::UnnamedType>> commitIfNeeded(const RefPtr<ResolvableTypeReference>& resolvableTypeReference) >+{ >+ auto& root = resolvableTypeReference->root(); >+ >+ AST::ResolvableType* preferredLiteralType = nullptr; >+ AST::UnnamedType* resolvedType = nullptr; >+ >+ bool first = true; >+ bool sawNullType = false; >+ root.forEachType([&] (AST::ResolvableType& type) { >+ if (resolvedType) { >+ ASSERT(type.maybeResolvedType()); >+ ASSERT(matches(*resolvedType, *type.maybeResolvedType())); >+ return; >+ } >+ >+ if (type.maybeResolvedType()) { >+ ASSERT(first); >+ resolvedType = type.maybeResolvedType(); >+ return; >+ } >+ >+ first = false; >+ >+ sawNullType |= is<AST::NullLiteralType>(type); >+ >+ // The type preference is ordered like so: >+ // {float} => float >+ // {int} => int >+ // {uint} => uint >+ // {int, uint} => int >+ // {float, uint} => float >+ // {float, int} => float >+ // {float, int, uint} => float >+ // >+ // This only comes into play when we don't have other type feedback. Currently, this >+ // only happens for anonymous ternary expressions, like: >+ // "(b ? 10.0 : 20);" >+ >+ if (!preferredLiteralType) { >+ preferredLiteralType = &type; >+ return; >+ } >+ >+ if (is<AST::FloatLiteralType>(type)) { >+ preferredLiteralType = &type; >+ return; >+ } >+ >+ if (is<AST::UnsignedIntegerLiteralType>(*preferredLiteralType) && is<AST::IntegerLiteralType>(type)) >+ preferredLiteralType = &type; >+ }); >+ >+ if (resolvedType) >+ return resolvedType->clone(); >+ >+ if (sawNullType) >+ return WTF::nullopt; >+ >+ AST::UnnamedType* preferredType; >+ if (is<AST::FloatLiteralType>(*preferredLiteralType)) >+ preferredType = &downcast<AST::FloatLiteralType>(*preferredLiteralType).preferredType(); >+ else if (is<AST::UnsignedIntegerLiteralType>(*preferredLiteralType)) >+ preferredType = &downcast<AST::UnsignedIntegerLiteralType>(*preferredLiteralType).preferredType(); >+ else if (is<AST::IntegerLiteralType>(*preferredLiteralType)) >+ preferredType = &downcast<AST::IntegerLiteralType>(*preferredLiteralType).preferredType(); >+ else >+ RELEASE_ASSERT_NOT_REACHED(); >+ >+ return matchAndCommit(&root, *preferredType); >+} >+ > bool Checker::assignTypes() > { > for (auto& keyValuePair : m_typeMap) { >@@ -541,11 +635,10 @@ bool Checker::assignTypes() > keyValuePair.key->setType(unnamedType->clone()); > return true; > }, [&](RefPtr<ResolvableTypeReference>& resolvableTypeReference) -> bool { >- if (!resolvableTypeReference->resolvableType().maybeResolvedType()) { >- if (!static_cast<bool>(commit(resolvableTypeReference->resolvableType()))) >- return false; >- } >- keyValuePair.key->setType(resolvableTypeReference->resolvableType().resolvedType().clone()); >+ auto resolvedType = commitIfNeeded(resolvableTypeReference); >+ if (!resolvedType) >+ return false; >+ keyValuePair.key->setType(WTFMove(resolvedType.value())); > return true; > })); > if (!success) >@@ -594,21 +687,28 @@ void Checker::visit(AST::FunctionDefinit > Visitor::visit(functionDefinition); > } > >-static Optional<UniqueRef<AST::UnnamedType>> matchAndCommit(ResolvingType& left, ResolvingType& right) >+static Optional<ResolvingType> matchAndCommit(ResolvingType& left, ResolvingType& right) > { >- return left.visit(WTF::makeVisitor([&](UniqueRef<AST::UnnamedType>& left) -> Optional<UniqueRef<AST::UnnamedType>> { >- return right.visit(WTF::makeVisitor([&](UniqueRef<AST::UnnamedType>& right) -> Optional<UniqueRef<AST::UnnamedType>> { >+ return left.visit(WTF::makeVisitor([&](UniqueRef<AST::UnnamedType>& left) -> Optional<ResolvingType> { >+ return right.visit(WTF::makeVisitor([&](UniqueRef<AST::UnnamedType>& right) -> Optional<ResolvingType> { > if (matches(left, right)) >- return left->clone(); >+ return ResolvingType(left->clone()); >+ return WTF::nullopt; >+ }, [&](RefPtr<ResolvableTypeReference>& right) -> Optional<ResolvingType> { >+ if (auto result = matchAndCommit(right, left.get())) >+ return ResolvingType(WTFMove(result.value())); > return WTF::nullopt; >- }, [&](RefPtr<ResolvableTypeReference>& right) -> Optional<UniqueRef<AST::UnnamedType>> { >- return matchAndCommit(left, right->resolvableType()); > })); >- }, [&](RefPtr<ResolvableTypeReference>& left) -> Optional<UniqueRef<AST::UnnamedType>> { >- return right.visit(WTF::makeVisitor([&](UniqueRef<AST::UnnamedType>& right) -> Optional<UniqueRef<AST::UnnamedType>> { >- return matchAndCommit(right, left->resolvableType()); >- }, [&](RefPtr<ResolvableTypeReference>& right) -> Optional<UniqueRef<AST::UnnamedType>> { >- return matchAndCommit(left->resolvableType(), right->resolvableType()); >+ }, [&](RefPtr<ResolvableTypeReference>& left) -> Optional<ResolvingType> { >+ return right.visit(WTF::makeVisitor([&](UniqueRef<AST::UnnamedType>& right) -> Optional<ResolvingType> { >+ if (auto result = matchAndCommit(left, right.get())) >+ return ResolvingType(WTFMove(result.value())); >+ return WTF::nullopt; >+ }, [&](RefPtr<ResolvableTypeReference>& right) -> Optional<ResolvingType> { >+ auto* result = new ResolvableTypeReference(left, right); >+ left->setParent(*result); >+ right->setParent(*result); >+ return ResolvingType(adoptRef(result)); > })); > })); > } >@@ -619,8 +719,8 @@ static Optional<UniqueRef<AST::UnnamedTy > if (matches(unnamedType, resolvingType)) > return unnamedType.clone(); > return WTF::nullopt; >- }, [&](RefPtr<ResolvableTypeReference>& resolvingType) -> Optional<UniqueRef<AST::UnnamedType>> { >- return matchAndCommit(unnamedType, resolvingType->resolvableType()); >+ }, [&](RefPtr<ResolvableTypeReference>& resolvableTypeReference) -> Optional<UniqueRef<AST::UnnamedType>> { >+ return matchAndCommit(resolvableTypeReference, unnamedType); > })); > } > >@@ -630,8 +730,8 @@ static Optional<UniqueRef<AST::UnnamedTy > if (matches(resolvingType, namedType)) > return resolvingType->clone(); > return WTF::nullopt; >- }, [&](RefPtr<ResolvableTypeReference>& resolvingType) -> Optional<UniqueRef<AST::UnnamedType>> { >- return matchAndCommit(namedType, resolvingType->resolvableType()); >+ }, [&](RefPtr<ResolvableTypeReference>& resolvableTypeReference) -> Optional<UniqueRef<AST::UnnamedType>> { >+ return matchAndCommit(resolvableTypeReference, namedType); > })); > } > >@@ -640,9 +740,7 @@ static Optional<UniqueRef<AST::UnnamedTy > return resolvingType.visit(WTF::makeVisitor([&](UniqueRef<AST::UnnamedType>& unnamedType) -> Optional<UniqueRef<AST::UnnamedType>> { > return unnamedType->clone(); > }, [&](RefPtr<ResolvableTypeReference>& resolvableTypeReference) -> Optional<UniqueRef<AST::UnnamedType>> { >- if (!resolvableTypeReference->resolvableType().maybeResolvedType()) >- return commit(resolvableTypeReference->resolvableType()); >- return resolvableTypeReference->resolvableType().resolvedType().clone(); >+ return commitIfNeeded(resolvableTypeReference); > })); > } > >@@ -800,7 +898,7 @@ void Checker::visit(AST::VariableDeclara > } > } > >-void Checker::assignType(AST::Expression& expression, UniqueRef<AST::UnnamedType>&& unnamedType, AST::TypeAnnotation typeAnnotation = AST::RightValue()) >+void Checker::assignType(AST::Expression& expression, UniqueRef<AST::UnnamedType>&& unnamedType, AST::TypeAnnotation typeAnnotation) > { > auto addResult = m_typeMap.add(&expression, std::make_unique<ResolvingType>(WTFMove(unnamedType))); > ASSERT_UNUSED(addResult, addResult.isNewEntry); >@@ -808,7 +906,7 @@ void Checker::assignType(AST::Expression > ASSERT_UNUSED(typeAnnotationAddResult, typeAnnotationAddResult.isNewEntry); > } > >-void Checker::assignType(AST::Expression& expression, RefPtr<ResolvableTypeReference>&& resolvableTypeReference, AST::TypeAnnotation typeAnnotation = AST::RightValue()) >+void Checker::assignType(AST::Expression& expression, RefPtr<ResolvableTypeReference>&& resolvableTypeReference, AST::TypeAnnotation typeAnnotation) > { > auto addResult = m_typeMap.add(&expression, std::make_unique<ResolvingType>(WTFMove(resolvableTypeReference))); > ASSERT_UNUSED(addResult, addResult.isNewEntry); >@@ -816,6 +914,15 @@ void Checker::assignType(AST::Expression > ASSERT_UNUSED(typeAnnotationAddResult, typeAnnotationAddResult.isNewEntry); > } > >+void Checker::assignType(AST::Expression& expression, ResolvingType resolvingType, AST::TypeAnnotation typeAnnotation) >+{ >+ return resolvingType.visit(WTF::makeVisitor([&](UniqueRef<AST::UnnamedType>& left) { >+ assignType(expression, WTFMove(left), typeAnnotation); >+ }, [&](RefPtr<ResolvableTypeReference>& left) { >+ assignType(expression, WTFMove(left), typeAnnotation); >+ })); >+} >+ > void Checker::forwardType(AST::Expression& expression, ResolvingType& resolvingType, AST::TypeAnnotation typeAnnotation = AST::RightValue()) > { > resolvingType.visit(WTF::makeVisitor([&](UniqueRef<AST::UnnamedType>& result) { >@@ -844,7 +951,7 @@ void Checker::visit(AST::AssignmentExpre > if (!rightInfo) > return; > >- auto resultType = matchAndCommit(leftInfo->resolvingType, rightInfo->resolvingType); >+ auto resultType = matchAndCommit(rightInfo->resolvingType, *leftInfo->resolvingType.getUnnamedType()); > if (!resultType) { > setError(); > return; >@@ -865,7 +972,7 @@ void Checker::visit(AST::ReadModifyWrite > if (!newValueInfo) > return; > >- if (Optional<UniqueRef<AST::UnnamedType>> matchedType = matchAndCommit(leftValueInfo->resolvingType, newValueInfo->resolvingType)) >+ if (Optional<UniqueRef<AST::UnnamedType>> matchedType = matchAndCommit(newValueInfo->resolvingType, *leftValueInfo->resolvingType.getUnnamedType())) > readModifyWriteExpression.newValue().setType(WTFMove(matchedType.value())); > else { > setError(); >@@ -883,9 +990,26 @@ static AST::UnnamedType* getUnnamedType( > { > return resolvingType.visit(WTF::makeVisitor([](UniqueRef<AST::UnnamedType>& type) -> AST::UnnamedType* { > return &type; >- }, [](RefPtr<ResolvableTypeReference>& type) -> AST::UnnamedType* { >+ }, [](RefPtr<ResolvableTypeReference>& resolvableTypeReference) -> AST::UnnamedType* { > // FIXME: If the type isn't committed, should we just commit() it now? >- return type->resolvableType().maybeResolvedType(); >+ AST::UnnamedType* result = nullptr; >+ bool ok = true; >+ resolvableTypeReference->forEachType([&] (AST::ResolvableType& type) { >+ if (!ok) { >+ ASSERT(!type.maybeResolvedType()); >+ return; >+ } >+ if (!type.maybeResolvedType()) { >+ ok = false; >+ return; >+ } >+ >+ if (!result) >+ result = type.maybeResolvedType(); >+ >+ ASSERT(matches(*result, *type.maybeResolvedType())); >+ }); >+ return ok ? result : nullptr; > })); > } > >@@ -1201,8 +1325,8 @@ bool Checker::isBoolType(ResolvingType& > { > return resolvingType.visit(WTF::makeVisitor([&](UniqueRef<AST::UnnamedType>& left) -> bool { > return matches(left, m_intrinsics.boolType()); >- }, [&](RefPtr<ResolvableTypeReference>& left) -> bool { >- return static_cast<bool>(matchAndCommit(m_intrinsics.boolType(), left->resolvableType())); >+ }, [&](RefPtr<ResolvableTypeReference>& resolvableTypeReference) -> bool { >+ return static_cast<bool>(matchAndCommit(resolvableTypeReference, static_cast<AST::NamedType&>(m_intrinsics.boolType()))); > })); > } > >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLInferTypes.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLInferTypes.cpp (revision 247086) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLInferTypes.cpp (working copy) >@@ -208,7 +208,12 @@ ALWAYS_INLINE bool inferTypesForCallImpl > auto success = argumentTypes[i].get().visit(WTF::makeVisitor([&](UniqueRef<AST::UnnamedType>& unnamedType) -> bool { > return matches(*possibleFunction.parameters()[i]->type(), unnamedType); > }, [&](RefPtr<ResolvableTypeReference>& resolvableTypeReference) -> bool { >- return resolvableTypeReference->resolvableType().canResolve(possibleFunction.parameters()[i]->type()->unifyNode()); >+ bool ok = true; >+ auto& unifyNode = possibleFunction.parameters()[i]->type()->unifyNode(); >+ resolvableTypeReference->forEachType([&] (AST::ResolvableType& type) { >+ ok &= type.canResolve(unifyNode); >+ }); >+ return ok; > })); > if (!success) > return false; >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLParser.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLParser.cpp (revision 247086) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLParser.cpp (working copy) >@@ -364,8 +364,7 @@ auto Parser::parseConstantExpression() - > auto value = floatLiteralToFloat(type->stringView); > if (!value) > return Unexpected<Error>(value.error()); >- return {{ AST::FloatLiteral(WTFMove(*type), *value) }}; >- } >+ return {{ AST::FloatLiteral(WTFMove(*type), *value) }}; } > case Lexer::Token::Type::Null: > return { AST::NullLiteral(WTFMove(*type)) }; > case Lexer::Token::Type::True: >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp (revision 247086) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp (working copy) >@@ -60,7 +60,7 @@ 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; > >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.cpp (revision 247086) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.cpp (working copy) >@@ -44,7 +44,12 @@ static unsigned conversionCost(AST::Func > conversionCost += argumentTypes[i].get().visit(WTF::makeVisitor([&](UniqueRef<AST::UnnamedType>&) -> unsigned { > return 0; > }, [&](RefPtr<ResolvableTypeReference>& resolvableTypeReference) -> unsigned { >- return resolvableTypeReference->resolvableType().conversionCost(*candidate.parameters()[i]->type()); >+ unsigned cost = 0; >+ resolvableTypeReference->forEachType([&] (AST::ResolvableType& type) { >+ // FIXME: Do we really want max here? We should specify what to do. >+ cost = std::max(cost, type.conversionCost(*candidate.parameters()[i]->type())); >+ }); >+ return cost; > })); > } > // The return type can never be a literal type, so its conversion cost is always 0. >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLResolvingType.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLResolvingType.h (revision 247086) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLResolvingType.h (working copy) >@@ -59,15 +59,50 @@ public: > { > } > >+ ResolvableTypeReference(RefPtr<ResolvableTypeReference> left, RefPtr<ResolvableTypeReference> right) >+ : m_left(WTFMove(left)) >+ , m_right(WTFMove(right)) >+ { >+ } >+ > ResolvableTypeReference(const ResolvableTypeReference&) = delete; > ResolvableTypeReference(ResolvableTypeReference&&) = delete; > ResolvableTypeReference& operator=(const ResolvableTypeReference&) = delete; > ResolvableTypeReference& operator=(ResolvableTypeReference&&) = delete; > >- AST::ResolvableType& resolvableType() { return *m_resolvableType; } >+ template <typename Function> >+ void forEachType(Function function) >+ { >+ if (m_resolvableType) >+ function(*m_resolvableType); >+ >+ if (m_left) { >+ ASSERT(m_right); >+ m_left->forEachType(function); >+ m_right->forEachType(function); >+ } else >+ ASSERT(!m_right); >+ } >+ >+ void setParent(ResolvableTypeReference& parent) >+ { >+ ASSERT(!m_parent); >+ m_parent = &parent; >+ } >+ >+ ResolvableTypeReference& root() >+ { >+ ResolvableTypeReference* result = this; >+ while (result->m_parent) >+ result = result->m_parent; >+ return *result; >+ } > > private: >- AST::ResolvableType* m_resolvableType; >+ AST::ResolvableType* m_resolvableType { nullptr }; >+ ResolvableTypeReference* m_parent { nullptr }; >+ RefPtr<ResolvableTypeReference> m_left; >+ RefPtr<ResolvableTypeReference> m_right; > }; > > // This is a thin wrapper around a Variant. >@@ -91,17 +126,10 @@ public: > } > > ResolvingType(const ResolvingType&) = delete; >- ResolvingType(ResolvingType&& other) >- : m_inner(WTFMove(other.m_inner)) >- { >- } >+ ResolvingType(ResolvingType&&) = default; > > ResolvingType& operator=(const ResolvingType&) = delete; >- ResolvingType& operator=(ResolvingType&& other) >- { >- m_inner = WTFMove(other.m_inner); >- return *this; >- } >+ ResolvingType& operator=(ResolvingType&& other) = default; > > AST::UnnamedType* getUnnamedType() > { >Index: LayoutTests/ChangeLog >=================================================================== >--- LayoutTests/ChangeLog (revision 247086) >+++ LayoutTests/ChangeLog (working copy) >@@ -1,3 +1,15 @@ >+2019-07-04 Saam Barati <sbarati@apple.com> >+ >+ [WHLSL] 'uint y = x ? 1 : 2' fails to typecheck >+ https://bugs.webkit.org/show_bug.cgi?id=199289 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * webgpu/whlsl-nested-resolvable-types-expected.txt: Added. >+ * webgpu/whlsl-nested-resolvable-types.html: Added. >+ * webgpu/whlsl-resolvable-types-should-fail-expected.txt: Added. >+ * webgpu/whlsl-resolvable-types-should-fail.html: Added. >+ > 2019-07-02 Fujii Hironori <Hironori.Fujii@sony.com> > > imported/blink/animations/display-inline-style-adjust.html isn't a valid ref test >Index: LayoutTests/webgpu/whlsl-nested-resolvable-types-expected.txt >=================================================================== >--- LayoutTests/webgpu/whlsl-nested-resolvable-types-expected.txt (nonexistent) >+++ LayoutTests/webgpu/whlsl-nested-resolvable-types-expected.txt (working copy) >@@ -0,0 +1,5 @@ >+PASS >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >Index: LayoutTests/webgpu/whlsl-nested-resolvable-types.html >=================================================================== >--- LayoutTests/webgpu/whlsl-nested-resolvable-types.html (nonexistent) >+++ LayoutTests/webgpu/whlsl-nested-resolvable-types.html (working copy) >@@ -0,0 +1,143 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<script src="../resources/js-test-pre.js"></script> >+<script src="js/webgpu-functions.js"></script> >+</head> >+<body> >+<script> >+const shaderSource = ` >+void doUint(uint x) >+{ >+} >+ >+void doInt(int x) >+{ >+} >+ >+void doFloat(float x) >+{ >+} >+ >+void jaz(float x) >+{ >+} >+ >+void doPtr(thread float* x) >+{ >+} >+ >+[numthreads(1, 1, 1)] >+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ bool b = true; >+ >+ (b ? 10.0 : 20); >+ (b ? 20 : 10.0); >+ (b ? (b ? 10 : (b ? 20 : 30)) : (b ? 10 : (b ? 40 : 20))); >+ (b ? (b ? 10 : (b ? 20.5 : 30)) : (b ? 10 : (b ? 40 : 20))); >+ (b ? (b ? 10 : (b ? 20.5 : 30)) : (b ? 10.5 : (b ? 40.5 : 20))); >+ >+ uint x = b ? 10 : 20; >+ uint x2 = b ? 2147483647 : 24; >+ doUint(b ? 10 : 20); >+ doUint(b ? (b ? 2147483647 : 10) : 20); >+ doUint(b ? (b ? 2147483647 : 10) : (b ? 20 : (b ? 45 : 55))); >+ >+ int x3 = b ? 450 : 42; >+ doInt(b ? 10 : 20); >+ doInt(b ? (b ? 2147483647 : 10) : (b ? 20 : (b ? 45 : 55))); >+ >+ float y = b ? 10.5 : 20; >+ float y2 = b ? (b ? 20 : 10.5) : 20; >+ doFloat(b ? (b ? 2147483647 : 10) : (b ? 20 : (b ? 45 : 55))); >+ doFloat(b ? (b ? 2147483647 : 10.5) : (b ? 20 : (b ? 45 : 55))); >+ >+ thread int* ptr = b ? null : null; >+ doPtr(b ? null : null); >+ doPtr(b ? (b ? null : null) : null); >+ doPtr(b ? (b ? null : null) : (b ? null : null)); >+ >+ int[42] array; >+ if (array[b ? (b ? 10 : 20) : (b ? 5 : 6)] != 0) >+ return; >+ >+ { >+ thread int* x; >+ if (x != (b ? (b ? null : null) : null)) >+ return; >+ } >+ >+ { >+ int value = 42; >+ thread int* ptr = &value; >+ int result = (b ? *ptr : 0); >+ if (result != 42) >+ return; >+ } >+ >+ buffer[0] = 1; >+} >+`; >+async function start(device) { >+ 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 size = Int32Array.BYTES_PER_ELEMENT * 1; >+ >+ const bufferDescriptor = {size, usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.TRANSFER_SRC}; >+ const buffer = device.createBuffer(bufferDescriptor); >+ const bufferArrayBuffer = await buffer.mapWriteAsync(); >+ const bufferFloat32Array = new Int32Array(bufferArrayBuffer); >+ bufferFloat32Array[0] = 0; >+ buffer.unmap(); >+ >+ const resultsBufferDescriptor = {size, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_READ}; >+ const resultsBuffer = device.createBuffer(resultsBufferDescriptor); >+ >+ const bufferBinding = {buffer: resultsBuffer, size}; >+ 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, size); >+ const computePassEncoder = commandEncoder.beginComputePass(); >+ computePassEncoder.setPipeline(computePipeline); >+ computePassEncoder.setBindGroup(0, bindGroup); >+ computePassEncoder.dispatch(1, 1, 1); >+ computePassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ const resultsArrayBuffer = await resultsBuffer.mapReadAsync(); >+ let resultsInt32Array = new Int32Array(resultsArrayBuffer); >+ if (resultsInt32Array[0] === 1) >+ testPassed(""); >+ else >+ testFailed(""); >+ resultsBuffer.unmap(); >+} >+window.jsTestIsAsync = true; >+getBasicDevice().then(function(device) { >+ start(device).then(function() { >+ finishJSTest(); >+ }, function() { >+ testFailed(""); >+ finishJSTest(); >+ }); >+}, function() { >+ testPassed(""); >+ finishJSTest(); >+}); >+</script> >+<script src="../resources/js-test-post.js"></script> >+</body> >+</html> >Index: LayoutTests/webgpu/whlsl-resolvable-types-should-fail-expected.txt >=================================================================== >--- LayoutTests/webgpu/whlsl-resolvable-types-should-fail-expected.txt (nonexistent) >+++ LayoutTests/webgpu/whlsl-resolvable-types-should-fail-expected.txt (working copy) >@@ -0,0 +1,5 @@ >+PASS >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >Index: LayoutTests/webgpu/whlsl-resolvable-types-should-fail.html >=================================================================== >--- LayoutTests/webgpu/whlsl-resolvable-types-should-fail.html (nonexistent) >+++ LayoutTests/webgpu/whlsl-resolvable-types-should-fail.html (working copy) >@@ -0,0 +1,202 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<script src="../resources/js-test-pre.js"></script> >+<script src="js/webgpu-functions.js"></script> >+</head> >+<body> >+<script> >+ >+async function shouldFail(source, device) { >+ const shaderModule = device.createShaderModule({code: source, 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 size = Int32Array.BYTES_PER_ELEMENT * 1; >+ >+ const bufferDescriptor = {size, usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.TRANSFER_SRC}; >+ const buffer = device.createBuffer(bufferDescriptor); >+ const bufferArrayBuffer = await buffer.mapWriteAsync(); >+ const bufferInt32Array = new Int32Array(bufferArrayBuffer); >+ bufferInt32Array[0] = 0; >+ buffer.unmap(); >+ >+ const resultsBufferDescriptor = {size, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_READ}; >+ const resultsBuffer = device.createBuffer(resultsBufferDescriptor); >+ >+ const bufferBinding = {buffer: resultsBuffer, size}; >+ 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, size); >+ const computePassEncoder = commandEncoder.beginComputePass(); >+ computePassEncoder.setPipeline(computePipeline); >+ computePassEncoder.setBindGroup(0, bindGroup); >+ computePassEncoder.dispatch(1, 1, 1); >+ computePassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ const resultsArrayBuffer = await resultsBuffer.mapReadAsync(); >+ let resultsInt32Array = new Int32Array(resultsArrayBuffer); >+ if (resultsInt32Array[0] !== 0) >+ throw new Error("Bad result: " + resultsInt32Array[0]) >+ resultsBuffer.unmap(); >+} >+ >+let tests = [ >+` >+[numthreads(1, 1, 1)] >+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ bool b = true; >+ (b ? null : null); >+ buffer[0] = 1; >+} >+`, >+` >+[numthreads(1, 1, 1)] >+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ bool b = true; >+ int x = 10.5; >+ buffer[0] = 1; >+} >+`, >+` >+[numthreads(1, 1, 1)] >+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ bool b = true; >+ int x = 10.0; >+ buffer[0] = 1; >+} >+`, >+` >+[numthreads(1, 1, 1)] >+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ bool b = true; >+ uint x = 10.0; >+ buffer[0] = 1; >+} >+`, >+` >+void foo(uint x) { } >+[numthreads(1, 1, 1)] >+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ bool b = true; >+ foo(10.0); >+ buffer[0] = 1; >+} >+`, >+` >+void foo(uint x) { } >+[numthreads(1, 1, 1)] >+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ bool b = true; >+ foo(b ? 10 : 1.0); >+ buffer[0] = 1; >+} >+`, >+` >+void foo(int x) { } >+[numthreads(1, 1, 1)] >+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ bool b = true; >+ foo(b ? 10 : 1.0); >+ buffer[0] = 1; >+} >+`, >+` >+[numthreads(1, 1, 1)] >+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ bool b = true; >+ uint x = -10; >+ buffer[0] = 1; >+} >+`, >+` >+void foo(uint x) { } >+[numthreads(1, 1, 1)] >+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ bool b = true; >+ foo(b ? (b ? 10 : 20) : (b ? (b ? -10 : 20) : 54)); >+ buffer[0] = 1; >+} >+`, >+` >+void foo(int x) { } >+[numthreads(1, 1, 1)] >+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ bool b = true; >+ foo(b ? (b ? 10 : 20) : (b ? (b ? 10.0 : 20) : 54)); >+ buffer[0] = 1; >+} >+`, >+` >+[numthreads(1, 1, 1)] >+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ bool b = true; >+ int x = b ? (b ? 10 : 20) : (b ? (b ? 10.0 : 20) : 54); >+ buffer[0] = 1; >+} >+`, >+` >+[numthreads(1, 1, 1)] >+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ bool b = true; >+ uint x = b ? (b ? 10 : 20) : (b ? (b ? 10.0 : 20) : 54); >+ buffer[0] = 1; >+} >+`, >+` >+[numthreads(1, 1, 1)] >+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ bool b = true; >+ int x = *(b ? null : null); >+ buffer[0] = 1; >+} >+`, >+` >+[numthreads(1, 1, 1)] >+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ bool b = true; >+ (b ? null : 10); >+ buffer[0] = 1; >+} >+`, >+` >+[numthreads(1, 1, 1)] >+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ bool b = true; >+ (b ? (b ? 20 : 30) : (b ? null : null)); >+ buffer[0] = 1; >+} >+` >+]; >+ >+window.jsTestIsAsync = true; >+getBasicDevice().then(async function(device) { >+ for (let test of tests) { >+ try { >+ await shouldFail(test, device); >+ } catch (e) { >+ testFailed("" + e); >+ } >+ } >+ testPassed(""); >+ finishJSTest(); >+}, function() { >+ testPassed(""); >+ finishJSTest(); >+}); >+</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 199289
:
373448
|
373449
|
373457
|
373458