-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WGSL] Initial implementation of operator overload resolution #9763
[WGSL] Initial implementation of operator overload resolution #9763
Conversation
EWS run on previous version of this PR (hash 12103b6) |
inline void log(Arguments&&... arguments) | ||
{ | ||
if (shouldDumpOverloadDebugInformation) | ||
dataLog(logPrefix, std::forward<Arguments>(arguments)...); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lol...
Source/WebGPU/WGSL/Overload.cpp
Outdated
|
||
FixedVector<std::optional<ViableOverload>> considerCandidates(); | ||
std::optional<ViableOverload> considerCandidate(const OverloadCandidate&); | ||
unsigned calculateCost(const AbstractType&, Type*); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way overload resolution works in WGSL doesn't have a cost function.
Firstly, only built-in functions are allowed to overload. User-written functions can't overload.
Secondly, all the built-in functions which are overloaded have mutually-exclusive signatures. There's never any situation where 2 function declarations are valid for a single call.
If you have something like sin(3.0)
, the literal 3.0 gets concretized according to concretization rules, which are not sensitive to the context that it's being passed to a function. So there's only a single correct overload after the concretization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's interesting. I tried to match the spec as closely as possible as described here: https://www.w3.org/TR/WGSL/#overload-resolution-section
Firstly, only built-in functions are allowed to overload.
This function doesn't assume anything about the overloads being user defined or builtins, but I don't see how assuming they are builtins wouldn't make the resolution any simpler.
Secondly, all the built-in functions which are overloaded have mutually-exclusive signatures. There's never any situation where 2 function declarations are valid for a single call.
That's true, but that doesn't mean that the same declaration can't yield more than one resolution. i.e. + (T, T) -> T
apply to 1 + 1
can resolve T
to AbstractInt
, i32
, u32
, AbstractFloat
, f32
or f16
, in that order of preference according to the conversion rank table.
If you have something like sin(3.0), the literal 3.0 gets concretized according to concretization rules, which are not sensitive to the context that it's being passed to a function. So there's only a single correct overload after the concretization.
You know the spec better than me, but that's not how I interpreted it. The way I understood it, overload resolution doesn't concretize types. e.g. const x = sin(3.0)
, x
should have type AbstractFloat
, but if we use var y = sin(3.0)
, now y
should have type f32
, according to the conversion rank function.
Maybe that's some nuance that I'm missing, and it can be implemented in a simpler way than described in the spec.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function doesn't assume anything about the overloads being user defined or builtins, but I don't see how assuming they are builtins wouldn't make the resolution any simpler.
It's a finite set - every member of every set of overload resolutions is known before we look at the first line of the user program.
That's interesting. I tried to match the spec as closely as possible as described here: https://www.w3.org/TR/WGSL/#overload-resolution-section
https://gpuweb.github.io/gpuweb/wgsl/#conversion-rank is totally new to me, I had no idea that there was a ranking algorithm. My background knowledge here comes from the fact that the CG wanted to forbid user functions from overriding each other, precisely because (IIRC) they didn't want to write a general ranking algorithm - they wanted to punt on that algorithm until after the initial version of the language. I guess my memory is out-of-date, since it seems pretty clear that a general ranking algorithm exists.
Sorry for the noise, I think your following the spec was the right thing to do.
Source/WebGPU/WGSL/Overload.cpp
Outdated
FixedVector<std::optional<ViableOverload>> considerCandidates(); | ||
std::optional<ViableOverload> considerCandidate(const OverloadCandidate&); | ||
unsigned calculateCost(const AbstractType&, Type*); | ||
unsigned conversionCost(Type*, Type*) const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WGSL types don't have implicit conversions, except for literals, so I'm not sure this is the right approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is supposed to match 1:1 the "Conversion Rank" table in the spec: https://www.w3.org/TR/WGSL/#conversion-rank
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should rename this to conversionRank
if we end up landing this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks pretty straightforward.
TypeVariable T { 0, TypeVariable::Number }; | ||
plus1.typeVariables.append(T); | ||
plus1.parameters.append(T); | ||
plus1.parameters.append(T); | ||
plus1.result = T; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way to represent this as data rather than C++? I assume there are going to be dozens of more stanzas like this. Can we generate them at build time? (or run time?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that's the plan. I'm hoping to do something similar to JSC's BytecodeList.rb
, where we declare all these in a file and output these C++ definitions at compile time.
Source/WebGPU/WGSL/WGSL.h
Outdated
@@ -47,15 +47,15 @@ class ShaderModule; | |||
struct SuccessfulCheck { | |||
SuccessfulCheck() = delete; | |||
SuccessfulCheck(SuccessfulCheck&&); | |||
SuccessfulCheck(Vector<Warning>&&, UniqueRef<ShaderModule>&&); | |||
SuccessfulCheck(WTF::Vector<Warning>&&, UniqueRef<ShaderModule>&&); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we rejigger our includes to make this not have to be changed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that was 100% a mistake, I'll upload a patch to move the types into their own namespace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Preferably WGSL::Type::Vector
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I moved it in #9976. Only I made it Types
, because I wanted Type
to remain the base class that lives in the top-level WGSL
namespace.
12103b6
to
6bbec1a
Compare
EWS run on previous version of this PR (hash 6bbec1a) |
6bbec1a
to
cef64cd
Compare
EWS run on previous version of this PR (hash cef64cd) |
cef64cd
to
06571ff
Compare
EWS run on current version of this PR (hash 06571ff) |
https://bugs.webkit.org/show_bug.cgi?id=251863 rdar://105133289 Reviewed by Myles C. Maxfield. First pass at adding support for overloaded operators and functions. For now, only `+` is implemented with 2 operators, and declaring the operations is very cumbersome, but the patch is fairly large as it is, so more convenient declarations will follow in a separate patch. * Source/WebGPU/WGSL/Overload.cpp: Added. (WGSL::log): (WGSL::logLn): (WGSL::OverloadResolver::OverloadResolver): (WGSL::OverloadResolver::resolve): (WGSL::OverloadResolver::materialize const): (WGSL::OverloadResolver::considerCandidates): (WGSL::OverloadResolver::considerCandidate): (WGSL::OverloadResolver::calculateCost): (WGSL::OverloadResolver::unify): (WGSL::OverloadResolver::assign): (WGSL::OverloadResolver::resolve const): (WGSL::OverloadResolver::conversionCost const): (WGSL::primitive_pair): (WGSL::OverloadResolver::conversionCostImpl const): (WGSL::resolveOverloads): (WTF::printInternal): * Source/WebGPU/WGSL/Overload.h: Copied from Source/WebGPU/WGSL/Types.h. * Source/WebGPU/WGSL/TypeCheck.cpp: (WGSL::TypeChecker::TypeChecker): (WGSL::TypeChecker::visit): (WGSL::TypeChecker::chooseOverload): * Source/WebGPU/WGSL/TypeStore.cpp: (WGSL::TypeStore::TypeStore): (WGSL::TypeStore::vectorType): (WGSL::TypeStore::matrixType): (WGSL::TypeStore::allocateConstructor): * Source/WebGPU/WGSL/TypeStore.h: * Source/WebGPU/WGSL/Types.h: * Source/WebGPU/WGSL/WGSL.h: * Source/WebGPU/WebGPU.xcodeproj/project.pbxproj: Canonical link: https://commits.webkit.org/260254@main
06571ff
to
387c1b1
Compare
Committed 260254@main (387c1b1): https://commits.webkit.org/260254@main Reviewed commits have been landed. Closing PR #9763 and removing active labels. |
387c1b1
06571ff
π§ͺ api-iosπ§ͺ api-gtk