Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 1 | // Copyright 2021 The Tint Authors. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | #include "src/intrinsic_table.h" |
| 16 | |
| 17 | #include <algorithm> |
| 18 | #include <limits> |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 19 | #include <unordered_map> |
| 20 | #include <utility> |
| 21 | |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 22 | #include "src/program_builder.h" |
Ben Clayton | 6a77236 | 2021-06-18 18:56:13 +0000 | [diff] [blame] | 23 | #include "src/sem/atomic_type.h" |
Ben Clayton | fd35aa8 | 2021-07-26 22:19:48 +0000 | [diff] [blame] | 24 | #include "src/sem/depth_multisampled_texture_type.h" |
Antonio Maiorano | aea9c68 | 2021-04-19 22:54:43 +0000 | [diff] [blame] | 25 | #include "src/sem/depth_texture_type.h" |
Brandon Jones | 145f865 | 2021-04-22 22:47:03 +0000 | [diff] [blame] | 26 | #include "src/sem/external_texture_type.h" |
Antonio Maiorano | aea9c68 | 2021-04-19 22:54:43 +0000 | [diff] [blame] | 27 | #include "src/sem/multisampled_texture_type.h" |
Ben Clayton | 71786c9 | 2021-06-03 16:07:34 +0000 | [diff] [blame] | 28 | #include "src/sem/pipeline_stage_set.h" |
Antonio Maiorano | aea9c68 | 2021-04-19 22:54:43 +0000 | [diff] [blame] | 29 | #include "src/sem/sampled_texture_type.h" |
| 30 | #include "src/sem/storage_texture_type.h" |
Ben Clayton | b478f97 | 2021-07-15 20:34:21 +0000 | [diff] [blame] | 31 | #include "src/utils/get_or_create.h" |
| 32 | #include "src/utils/hash.h" |
Ben Clayton | 053559d | 2021-07-23 16:43:01 +0000 | [diff] [blame] | 33 | #include "src/utils/math.h" |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 34 | #include "src/utils/scoped_assignment.h" |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 35 | |
| 36 | namespace tint { |
| 37 | namespace { |
| 38 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 39 | // Forward declarations |
| 40 | struct OverloadInfo; |
| 41 | class Matchers; |
| 42 | class NumberMatcher; |
| 43 | class TypeMatcher; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 44 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 45 | /// A special type that matches all TypeMatchers |
| 46 | class Any : public Castable<Any, sem::Type> { |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 47 | public: |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 48 | Any() = default; |
| 49 | ~Any() override = default; |
| 50 | std::string type_name() const override { return "<any>"; } |
| 51 | std::string FriendlyName(const SymbolTable&) const override { |
| 52 | return "<any>"; |
| 53 | } |
| 54 | }; |
| 55 | |
| 56 | /// Number is an 32 bit unsigned integer, which can be in one of three states: |
| 57 | /// * Invalid - Number has not been assigned a value |
| 58 | /// * Valid - a fixed integer value |
| 59 | /// * Any - matches any other non-invalid number |
| 60 | struct Number { |
| 61 | static const Number any; |
| 62 | static const Number invalid; |
| 63 | |
| 64 | /// Constructed as a valid number with the value v |
| 65 | explicit Number(uint32_t v) : value_(v), state_(kValid) {} |
| 66 | |
| 67 | /// @returns the value of the number |
| 68 | inline uint32_t Value() const { return value_; } |
| 69 | |
| 70 | /// @returns the true if the number is valid |
| 71 | inline bool IsValid() const { return state_ == kValid; } |
| 72 | |
| 73 | /// @returns the true if the number is any |
| 74 | inline bool IsAny() const { return state_ == kAny; } |
| 75 | |
| 76 | /// Assignment operator. |
| 77 | /// The number becomes valid, with the value n |
| 78 | inline Number& operator=(uint32_t n) { |
| 79 | value_ = n; |
| 80 | state_ = kValid; |
| 81 | return *this; |
| 82 | } |
| 83 | |
| 84 | private: |
| 85 | enum State { |
| 86 | kInvalid, |
| 87 | kValid, |
| 88 | kAny, |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 89 | }; |
| 90 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 91 | constexpr explicit Number(State state) : state_(state) {} |
| 92 | |
| 93 | uint32_t value_ = 0; |
| 94 | State state_ = kInvalid; |
| 95 | }; |
| 96 | |
| 97 | const Number Number::any{Number::kAny}; |
| 98 | const Number Number::invalid{Number::kInvalid}; |
| 99 | |
| 100 | /// ClosedState holds the state of the open / closed numbers and types. |
| 101 | /// Used by the MatchState. |
| 102 | class ClosedState { |
| 103 | public: |
| 104 | explicit ClosedState(ProgramBuilder& b) : builder(b) {} |
| 105 | |
| 106 | /// If the type with index `idx` is open, then it is closed with type `ty` and |
| 107 | /// Type() returns true. If the type is closed, then `Type()` returns true iff |
| 108 | /// it is equal to `ty`. |
| 109 | bool Type(uint32_t idx, const sem::Type* ty) { |
| 110 | auto res = types_.emplace(idx, ty); |
| 111 | return res.second || res.first->second == ty; |
| 112 | } |
| 113 | |
| 114 | /// If the number with index `idx` is open, then it is closed with number |
| 115 | /// `number` and Num() returns true. If the number is closed, then `Num()` |
| 116 | /// returns true iff it is equal to `ty`. |
| 117 | bool Num(uint32_t idx, Number number) { |
| 118 | auto res = numbers_.emplace(idx, number.Value()); |
| 119 | return res.second || res.first->second == number.Value(); |
| 120 | } |
| 121 | |
| 122 | /// Type returns the closed type with index `idx`. |
| 123 | /// An ICE is raised if the type is not closed. |
| 124 | const sem::Type* Type(uint32_t idx) const { |
| 125 | auto it = types_.find(idx); |
| 126 | if (it == types_.end()) { |
Ben Clayton | ffd28e2 | 2021-06-24 11:27:36 +0000 | [diff] [blame] | 127 | TINT_ICE(Resolver, builder.Diagnostics()) |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 128 | << "type with index " << idx << " is not closed"; |
| 129 | return nullptr; |
| 130 | } |
Ben Clayton | ffd28e2 | 2021-06-24 11:27:36 +0000 | [diff] [blame] | 131 | TINT_ASSERT(Resolver, it != types_.end()); |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 132 | return it->second; |
| 133 | } |
| 134 | |
| 135 | /// Type returns the number type with index `idx`. |
| 136 | /// An ICE is raised if the number is not closed. |
| 137 | Number Num(uint32_t idx) const { |
| 138 | auto it = numbers_.find(idx); |
| 139 | if (it == numbers_.end()) { |
Ben Clayton | ffd28e2 | 2021-06-24 11:27:36 +0000 | [diff] [blame] | 140 | TINT_ICE(Resolver, builder.Diagnostics()) |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 141 | << "number with index " << idx << " is not closed"; |
| 142 | return Number::invalid; |
| 143 | } |
| 144 | return Number(it->second); |
| 145 | } |
| 146 | |
| 147 | private: |
| 148 | ProgramBuilder& builder; |
| 149 | std::unordered_map<uint32_t, const sem::Type*> types_; |
| 150 | std::unordered_map<uint32_t, uint32_t> numbers_; |
| 151 | }; |
| 152 | |
| 153 | /// Index type used for matcher indices |
| 154 | using MatcherIndex = uint8_t; |
| 155 | |
| 156 | /// Index value used for open types / numbers that do not have a constraint |
| 157 | constexpr MatcherIndex kNoMatcher = std::numeric_limits<MatcherIndex>::max(); |
| 158 | |
| 159 | /// MatchState holds the state used to match an overload. |
| 160 | class MatchState { |
| 161 | public: |
| 162 | MatchState(ProgramBuilder& b, |
| 163 | ClosedState& c, |
| 164 | const Matchers& m, |
| 165 | const OverloadInfo& o, |
| 166 | MatcherIndex const* matcher_indices) |
| 167 | : builder(b), |
| 168 | closed(c), |
| 169 | matchers(m), |
| 170 | overload(o), |
| 171 | matcher_indices_(matcher_indices) {} |
| 172 | |
| 173 | /// The program builder |
| 174 | ProgramBuilder& builder; |
| 175 | /// The open / closed types and numbers |
| 176 | ClosedState& closed; |
| 177 | /// The type and number matchers |
| 178 | Matchers const& matchers; |
| 179 | /// The current overload being evaluated |
| 180 | OverloadInfo const& overload; |
| 181 | |
| 182 | /// Type uses the next TypeMatcher from the matcher indices to match the type |
| 183 | /// `ty`. If the type matches, the canonical expected type is returned. If the |
| 184 | /// type `ty` does not match, then nullptr is returned. |
| 185 | /// @note: The matcher indices are progressed on calling. |
| 186 | const sem::Type* Type(const sem::Type* ty); |
| 187 | |
| 188 | /// Num uses the next NumMatcher from the matcher indices to match the number |
| 189 | /// `num`. If the number matches, the canonical expected number is returned. |
| 190 | /// If the number `num` does not match, then an invalid number is returned. |
| 191 | /// @note: The matcher indices are progressed on calling. |
| 192 | Number Num(Number num); |
| 193 | |
| 194 | /// @returns a string representation of the next TypeMatcher from the matcher |
| 195 | /// indices. |
| 196 | /// @note: The matcher indices are progressed on calling. |
| 197 | std::string TypeName(); |
| 198 | |
| 199 | /// @returns a string representation of the next NumberMatcher from the |
| 200 | /// matcher indices. |
| 201 | /// @note: The matcher indices are progressed on calling. |
| 202 | std::string NumName(); |
| 203 | |
| 204 | private: |
| 205 | MatcherIndex const* matcher_indices_ = nullptr; |
| 206 | }; |
| 207 | |
| 208 | /// A TypeMatcher is the interface used to match an type used as part of an |
| 209 | /// overload's parameter or return type. |
| 210 | class TypeMatcher { |
| 211 | public: |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 212 | /// Destructor |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 213 | virtual ~TypeMatcher() = default; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 214 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 215 | /// Checks whether the given type matches the matcher rules, and returns the |
| 216 | /// expected, canonicalized type on success. |
| 217 | /// Match may close open types and numbers in state. |
| 218 | /// @param type the type to match |
| 219 | /// @returns the canonicalized type on match, otherwise nullptr |
| 220 | virtual const sem::Type* Match(MatchState& state, |
| 221 | const sem::Type* type) const = 0; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 222 | |
| 223 | /// @return a string representation of the matcher. Used for printing error |
| 224 | /// messages when no overload is found. |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 225 | virtual std::string String(MatchState& state) const = 0; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 226 | }; |
| 227 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 228 | /// A NumberMatcher is the interface used to match a number or enumerator used |
| 229 | /// as part of an overload's parameter or return type. |
| 230 | class NumberMatcher { |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 231 | public: |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 232 | /// Destructor |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 233 | virtual ~NumberMatcher() = default; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 234 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 235 | /// Checks whether the given number matches the matcher rules. |
| 236 | /// Match may close open numbers in state. |
| 237 | /// @param number the number to match |
| 238 | /// @returns true if the argument type is as expected. |
| 239 | virtual Number Match(MatchState& state, Number number) const = 0; |
| 240 | |
| 241 | /// @return a string representation of the matcher. Used for printing error |
| 242 | /// messages when no overload is found. |
| 243 | virtual std::string String(MatchState& state) const = 0; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 244 | }; |
| 245 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 246 | /// OpenTypeMatcher is a Matcher for an open type. |
| 247 | /// The OpenTypeMatcher will match against any type (so long as it is consistent |
| 248 | /// across all uses in the overload) |
| 249 | class OpenTypeMatcher : public TypeMatcher { |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 250 | public: |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 251 | /// Constructor |
| 252 | explicit OpenTypeMatcher(uint32_t index) : index_(index) {} |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 253 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 254 | const sem::Type* Match(MatchState& state, |
| 255 | const sem::Type* type) const override { |
| 256 | if (type->Is<Any>()) { |
| 257 | return state.closed.Type(index_); |
| 258 | } |
| 259 | return state.closed.Type(index_, type) ? type : nullptr; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 260 | } |
| 261 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 262 | std::string String(MatchState& state) const override; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 263 | |
| 264 | private: |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 265 | uint32_t index_; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 266 | }; |
| 267 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 268 | /// OpenNumberMatcher is a Matcher for an open number. |
| 269 | /// The OpenNumberMatcher will match against any number (so long as it is |
| 270 | /// consistent for the overload) |
| 271 | class OpenNumberMatcher : public NumberMatcher { |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 272 | public: |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 273 | explicit OpenNumberMatcher(uint32_t index) : index_(index) {} |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 274 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 275 | Number Match(MatchState& state, Number number) const override { |
| 276 | if (number.IsAny()) { |
| 277 | return state.closed.Num(index_); |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 278 | } |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 279 | return state.closed.Num(index_, number) ? number : Number::invalid; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 280 | } |
| 281 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 282 | std::string String(MatchState& state) const override; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 283 | |
| 284 | private: |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 285 | uint32_t index_; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 286 | }; |
| 287 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 288 | //////////////////////////////////////////////////////////////////////////////// |
| 289 | // Binding functions for use in the generated intrinsic_table.inl |
| 290 | // TODO(bclayton): See if we can move more of this hand-rolled code to the |
| 291 | // template |
| 292 | //////////////////////////////////////////////////////////////////////////////// |
| 293 | using TexelFormat = ast::ImageFormat; |
Ben Clayton | 93e8f52 | 2021-06-04 20:41:47 +0000 | [diff] [blame] | 294 | using Access = ast::Access; |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 295 | using StorageClass = ast::StorageClass; |
| 296 | using ParameterUsage = sem::ParameterUsage; |
Ben Clayton | 71786c9 | 2021-06-03 16:07:34 +0000 | [diff] [blame] | 297 | using PipelineStageSet = sem::PipelineStageSet; |
| 298 | using PipelineStage = ast::PipelineStage; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 299 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 300 | bool match_bool(const sem::Type* ty) { |
| 301 | return ty->IsAnyOf<Any, sem::Bool>(); |
| 302 | } |
| 303 | |
| 304 | const sem::Bool* build_bool(MatchState& state) { |
| 305 | return state.builder.create<sem::Bool>(); |
| 306 | } |
| 307 | |
| 308 | bool match_f32(const sem::Type* ty) { |
| 309 | return ty->IsAnyOf<Any, sem::F32>(); |
| 310 | } |
| 311 | |
| 312 | const sem::I32* build_i32(MatchState& state) { |
| 313 | return state.builder.create<sem::I32>(); |
| 314 | } |
| 315 | |
| 316 | bool match_i32(const sem::Type* ty) { |
| 317 | return ty->IsAnyOf<Any, sem::I32>(); |
| 318 | } |
| 319 | |
| 320 | const sem::U32* build_u32(MatchState& state) { |
| 321 | return state.builder.create<sem::U32>(); |
| 322 | } |
| 323 | |
| 324 | bool match_u32(const sem::Type* ty) { |
| 325 | return ty->IsAnyOf<Any, sem::U32>(); |
| 326 | } |
| 327 | |
| 328 | const sem::F32* build_f32(MatchState& state) { |
| 329 | return state.builder.create<sem::F32>(); |
| 330 | } |
| 331 | |
| 332 | bool match_vec(const sem::Type* ty, Number& N, const sem::Type*& T) { |
| 333 | if (ty->Is<Any>()) { |
| 334 | N = Number::any; |
| 335 | T = ty; |
| 336 | return true; |
| 337 | } |
| 338 | |
| 339 | if (auto* v = ty->As<sem::Vector>()) { |
Ben Clayton | f5ed2ba | 2021-07-22 18:31:34 +0000 | [diff] [blame] | 340 | N = v->Width(); |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 341 | T = v->type(); |
| 342 | return true; |
| 343 | } |
| 344 | return false; |
| 345 | } |
| 346 | |
| 347 | const sem::Vector* build_vec(MatchState& state, Number N, const sem::Type* el) { |
| 348 | return state.builder.create<sem::Vector>(el, N.Value()); |
| 349 | } |
| 350 | |
| 351 | template <int N> |
| 352 | bool match_vec(const sem::Type* ty, const sem::Type*& T) { |
| 353 | if (ty->Is<Any>()) { |
| 354 | T = ty; |
| 355 | return true; |
| 356 | } |
| 357 | |
| 358 | if (auto* v = ty->As<sem::Vector>()) { |
Ben Clayton | f5ed2ba | 2021-07-22 18:31:34 +0000 | [diff] [blame] | 359 | if (v->Width() == N) { |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 360 | T = v->type(); |
| 361 | return true; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 362 | } |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 363 | } |
| 364 | return false; |
| 365 | } |
| 366 | |
| 367 | bool match_vec2(const sem::Type* ty, const sem::Type*& T) { |
| 368 | return match_vec<2>(ty, T); |
| 369 | } |
| 370 | |
| 371 | const sem::Vector* build_vec2(MatchState& state, const sem::Type* T) { |
| 372 | return build_vec(state, Number(2), T); |
| 373 | } |
| 374 | |
| 375 | bool match_vec3(const sem::Type* ty, const sem::Type*& T) { |
| 376 | return match_vec<3>(ty, T); |
| 377 | } |
| 378 | |
| 379 | const sem::Vector* build_vec3(MatchState& state, const sem::Type* T) { |
| 380 | return build_vec(state, Number(3), T); |
| 381 | } |
| 382 | |
| 383 | bool match_vec4(const sem::Type* ty, const sem::Type*& T) { |
| 384 | return match_vec<4>(ty, T); |
| 385 | } |
| 386 | |
| 387 | const sem::Vector* build_vec4(MatchState& state, const sem::Type* T) { |
| 388 | return build_vec(state, Number(4), T); |
| 389 | } |
| 390 | |
| 391 | bool match_mat(const sem::Type* ty, Number& M, Number& N, const sem::Type*& T) { |
| 392 | if (ty->Is<Any>()) { |
| 393 | M = Number::any; |
| 394 | N = Number::any; |
| 395 | T = ty; |
| 396 | return true; |
| 397 | } |
| 398 | if (auto* m = ty->As<sem::Matrix>()) { |
| 399 | M = m->columns(); |
Ben Clayton | f5ed2ba | 2021-07-22 18:31:34 +0000 | [diff] [blame] | 400 | N = m->ColumnType()->Width(); |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 401 | T = m->type(); |
| 402 | return true; |
| 403 | } |
| 404 | return false; |
| 405 | } |
| 406 | |
| 407 | const sem::Matrix* build_mat(MatchState& state, |
| 408 | Number N, |
| 409 | Number M, |
| 410 | const sem::Type* T) { |
Ben Clayton | 0a2b5f2 | 2021-06-09 14:32:14 +0000 | [diff] [blame] | 411 | auto* column_type = state.builder.create<sem::Vector>(T, M.Value()); |
| 412 | return state.builder.create<sem::Matrix>(column_type, N.Value()); |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 413 | } |
| 414 | |
| 415 | bool match_array(const sem::Type* ty, const sem::Type*& T) { |
| 416 | if (ty->Is<Any>()) { |
| 417 | T = ty; |
| 418 | return true; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 419 | } |
| 420 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 421 | if (auto* a = ty->As<sem::Array>()) { |
| 422 | if (a->Count() == 0) { |
| 423 | T = a->ElemType(); |
| 424 | return true; |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 425 | } |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 426 | } |
| 427 | return false; |
| 428 | } |
| 429 | |
| 430 | const sem::Array* build_array(MatchState& state, const sem::Type* el) { |
| 431 | return state.builder.create<sem::Array>(el, |
| 432 | /* count */ 0, |
| 433 | /* align */ 0, |
| 434 | /* size */ 0, |
| 435 | /* stride */ 0, |
| 436 | /* stride_implicit */ 0); |
| 437 | } |
| 438 | |
Ben Clayton | 1858854 | 2021-06-04 22:17:37 +0000 | [diff] [blame] | 439 | bool match_ptr(const sem::Type* ty, Number& S, const sem::Type*& T, Number& A) { |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 440 | if (ty->Is<Any>()) { |
| 441 | S = Number::any; |
| 442 | T = ty; |
Ben Clayton | 1858854 | 2021-06-04 22:17:37 +0000 | [diff] [blame] | 443 | A = Number::any; |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 444 | return true; |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 445 | } |
| 446 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 447 | if (auto* p = ty->As<sem::Pointer>()) { |
| 448 | S = Number(static_cast<uint32_t>(p->StorageClass())); |
| 449 | T = p->StoreType(); |
Ben Clayton | 1858854 | 2021-06-04 22:17:37 +0000 | [diff] [blame] | 450 | A = Number(static_cast<uint32_t>(p->Access())); |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 451 | return true; |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 452 | } |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 453 | return false; |
| 454 | } |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 455 | |
Ben Clayton | 1858854 | 2021-06-04 22:17:37 +0000 | [diff] [blame] | 456 | const sem::Pointer* build_ptr(MatchState& state, |
| 457 | Number S, |
| 458 | const sem::Type* T, |
| 459 | Number& A) { |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 460 | return state.builder.create<sem::Pointer>( |
Ben Clayton | 1858854 | 2021-06-04 22:17:37 +0000 | [diff] [blame] | 461 | T, static_cast<ast::StorageClass>(S.Value()), |
| 462 | static_cast<ast::Access>(A.Value())); |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 463 | } |
| 464 | |
Ben Clayton | 6a77236 | 2021-06-18 18:56:13 +0000 | [diff] [blame] | 465 | bool match_atomic(const sem::Type* ty, const sem::Type*& T) { |
| 466 | if (ty->Is<Any>()) { |
| 467 | T = ty; |
| 468 | return true; |
| 469 | } |
| 470 | |
| 471 | if (auto* a = ty->As<sem::Atomic>()) { |
| 472 | T = a->Type(); |
| 473 | return true; |
| 474 | } |
| 475 | return false; |
| 476 | } |
| 477 | |
| 478 | const sem::Atomic* build_atomic(MatchState& state, const sem::Type* T) { |
| 479 | return state.builder.create<sem::Atomic>(T); |
| 480 | } |
| 481 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 482 | bool match_sampler(const sem::Type* ty) { |
| 483 | if (ty->Is<Any>()) { |
| 484 | return true; |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 485 | } |
Ben Clayton | 367f5df | 2021-08-23 15:16:42 +0000 | [diff] [blame] | 486 | return ty->Is([](const sem::Sampler* s) { |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 487 | return s->kind() == ast::SamplerKind::kSampler; |
| 488 | }); |
| 489 | } |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 490 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 491 | const sem::Sampler* build_sampler(MatchState& state) { |
| 492 | return state.builder.create<sem::Sampler>(ast::SamplerKind::kSampler); |
| 493 | } |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 494 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 495 | bool match_sampler_comparison(const sem::Type* ty) { |
| 496 | if (ty->Is<Any>()) { |
| 497 | return true; |
| 498 | } |
Ben Clayton | 367f5df | 2021-08-23 15:16:42 +0000 | [diff] [blame] | 499 | return ty->Is([](const sem::Sampler* s) { |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 500 | return s->kind() == ast::SamplerKind::kComparisonSampler; |
| 501 | }); |
| 502 | } |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 503 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 504 | const sem::Sampler* build_sampler_comparison(MatchState& state) { |
| 505 | return state.builder.create<sem::Sampler>( |
| 506 | ast::SamplerKind::kComparisonSampler); |
| 507 | } |
| 508 | |
| 509 | bool match_texture(const sem::Type* ty, |
| 510 | ast::TextureDimension dim, |
| 511 | const sem::Type*& T) { |
| 512 | if (ty->Is<Any>()) { |
| 513 | T = ty; |
| 514 | return true; |
| 515 | } |
| 516 | if (auto* v = ty->As<sem::SampledTexture>()) { |
| 517 | if (v->dim() == dim) { |
| 518 | T = v->type(); |
| 519 | return true; |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 520 | } |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 521 | } |
| 522 | return false; |
| 523 | } |
| 524 | |
| 525 | #define JOIN(a, b) a##b |
| 526 | |
| 527 | #define DECLARE_SAMPLED_TEXTURE(suffix, dim) \ |
| 528 | bool JOIN(match_texture_, suffix)(const sem::Type* ty, \ |
| 529 | const sem::Type*& T) { \ |
| 530 | return match_texture(ty, dim, T); \ |
| 531 | } \ |
| 532 | const sem::SampledTexture* JOIN(build_texture_, suffix)( \ |
| 533 | MatchState & state, const sem::Type* T) { \ |
| 534 | return state.builder.create<sem::SampledTexture>(dim, T); \ |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 535 | } |
| 536 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 537 | DECLARE_SAMPLED_TEXTURE(1d, ast::TextureDimension::k1d) |
| 538 | DECLARE_SAMPLED_TEXTURE(2d, ast::TextureDimension::k2d) |
| 539 | DECLARE_SAMPLED_TEXTURE(2d_array, ast::TextureDimension::k2dArray) |
| 540 | DECLARE_SAMPLED_TEXTURE(3d, ast::TextureDimension::k3d) |
| 541 | DECLARE_SAMPLED_TEXTURE(cube, ast::TextureDimension::kCube) |
| 542 | DECLARE_SAMPLED_TEXTURE(cube_array, ast::TextureDimension::kCubeArray) |
| 543 | #undef DECLARE_SAMPLED_TEXTURE |
| 544 | |
| 545 | bool match_texture_multisampled(const sem::Type* ty, |
| 546 | ast::TextureDimension dim, |
| 547 | const sem::Type*& T) { |
| 548 | if (ty->Is<Any>()) { |
| 549 | T = ty; |
| 550 | return true; |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 551 | } |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 552 | if (auto* v = ty->As<sem::MultisampledTexture>()) { |
| 553 | if (v->dim() == dim) { |
| 554 | T = v->type(); |
| 555 | return true; |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 556 | } |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 557 | } |
| 558 | return false; |
| 559 | } |
| 560 | |
| 561 | #define DECLARE_MULTISAMPLED_TEXTURE(suffix, dim) \ |
| 562 | bool JOIN(match_texture_multisampled_, suffix)(const sem::Type* ty, \ |
| 563 | const sem::Type*& T) { \ |
| 564 | return match_texture_multisampled(ty, dim, T); \ |
| 565 | } \ |
| 566 | const sem::MultisampledTexture* JOIN(build_texture_multisampled_, suffix)( \ |
| 567 | MatchState & state, const sem::Type* T) { \ |
| 568 | return state.builder.create<sem::MultisampledTexture>(dim, T); \ |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 569 | } |
| 570 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 571 | DECLARE_MULTISAMPLED_TEXTURE(2d, ast::TextureDimension::k2d) |
| 572 | #undef DECLARE_MULTISAMPLED_TEXTURE |
| 573 | |
| 574 | bool match_texture_depth(const sem::Type* ty, ast::TextureDimension dim) { |
| 575 | if (ty->Is<Any>()) { |
| 576 | return true; |
| 577 | } |
Ben Clayton | 367f5df | 2021-08-23 15:16:42 +0000 | [diff] [blame] | 578 | return ty->Is([&](const sem::DepthTexture* t) { return t->dim() == dim; }); |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 579 | } |
| 580 | |
| 581 | #define DECLARE_DEPTH_TEXTURE(suffix, dim) \ |
| 582 | bool JOIN(match_texture_depth_, suffix)(const sem::Type* ty) { \ |
| 583 | return match_texture_depth(ty, dim); \ |
| 584 | } \ |
| 585 | const sem::DepthTexture* JOIN(build_texture_depth_, \ |
| 586 | suffix)(MatchState & state) { \ |
| 587 | return state.builder.create<sem::DepthTexture>(dim); \ |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 588 | } |
| 589 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 590 | DECLARE_DEPTH_TEXTURE(2d, ast::TextureDimension::k2d) |
| 591 | DECLARE_DEPTH_TEXTURE(2d_array, ast::TextureDimension::k2dArray) |
| 592 | DECLARE_DEPTH_TEXTURE(cube, ast::TextureDimension::kCube) |
| 593 | DECLARE_DEPTH_TEXTURE(cube_array, ast::TextureDimension::kCubeArray) |
| 594 | #undef DECLARE_DEPTH_TEXTURE |
| 595 | |
Ben Clayton | fd35aa8 | 2021-07-26 22:19:48 +0000 | [diff] [blame] | 596 | bool match_texture_depth_multisampled_2d(const sem::Type* ty) { |
| 597 | if (ty->Is<Any>()) { |
| 598 | return true; |
| 599 | } |
Ben Clayton | 367f5df | 2021-08-23 15:16:42 +0000 | [diff] [blame] | 600 | return ty->Is([&](const sem::DepthMultisampledTexture* t) { |
| 601 | return t->dim() == ast::TextureDimension::k2d; |
| 602 | }); |
Ben Clayton | fd35aa8 | 2021-07-26 22:19:48 +0000 | [diff] [blame] | 603 | } |
| 604 | |
| 605 | sem::DepthMultisampledTexture* build_texture_depth_multisampled_2d( |
| 606 | MatchState& state) { |
| 607 | return state.builder.create<sem::DepthMultisampledTexture>( |
| 608 | ast::TextureDimension::k2d); |
| 609 | } |
| 610 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 611 | bool match_texture_storage(const sem::Type* ty, |
| 612 | ast::TextureDimension dim, |
| 613 | Number& F, |
| 614 | Number& A) { |
| 615 | if (ty->Is<Any>()) { |
| 616 | F = Number::any; |
| 617 | A = Number::any; |
| 618 | return true; |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 619 | } |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 620 | if (auto* v = ty->As<sem::StorageTexture>()) { |
| 621 | if (v->dim() == dim) { |
| 622 | F = Number(static_cast<uint32_t>(v->image_format())); |
Ben Clayton | 93e8f52 | 2021-06-04 20:41:47 +0000 | [diff] [blame] | 623 | A = Number(static_cast<uint32_t>(v->access())); |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 624 | return true; |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 625 | } |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 626 | } |
| 627 | return false; |
| 628 | } |
| 629 | |
| 630 | #define DECLARE_STORAGE_TEXTURE(suffix, dim) \ |
| 631 | bool JOIN(match_texture_storage_, suffix)(const sem::Type* ty, Number& F, \ |
| 632 | Number& A) { \ |
| 633 | return match_texture_storage(ty, dim, F, A); \ |
| 634 | } \ |
| 635 | const sem::StorageTexture* JOIN(build_texture_storage_, suffix)( \ |
| 636 | MatchState & state, Number F, Number A) { \ |
| 637 | auto format = static_cast<TexelFormat>(F.Value()); \ |
Ben Clayton | 93e8f52 | 2021-06-04 20:41:47 +0000 | [diff] [blame] | 638 | auto access = static_cast<Access>(A.Value()); \ |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 639 | auto* T = sem::StorageTexture::SubtypeFor(format, state.builder.Types()); \ |
| 640 | return state.builder.create<sem::StorageTexture>(dim, format, access, T); \ |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 641 | } |
| 642 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 643 | DECLARE_STORAGE_TEXTURE(1d, ast::TextureDimension::k1d) |
| 644 | DECLARE_STORAGE_TEXTURE(2d, ast::TextureDimension::k2d) |
| 645 | DECLARE_STORAGE_TEXTURE(2d_array, ast::TextureDimension::k2dArray) |
| 646 | DECLARE_STORAGE_TEXTURE(3d, ast::TextureDimension::k3d) |
| 647 | #undef DECLARE_STORAGE_TEXTURE |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 648 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 649 | bool match_texture_external(const sem::Type* ty) { |
| 650 | return ty->IsAnyOf<Any, sem::ExternalTexture>(); |
| 651 | } |
Antonio Maiorano | dc4e6c1 | 2021-05-14 17:51:13 +0000 | [diff] [blame] | 652 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 653 | const sem::ExternalTexture* build_texture_external(MatchState& state) { |
| 654 | return state.builder.create<sem::ExternalTexture>(); |
| 655 | } |
Antonio Maiorano | dc4e6c1 | 2021-05-14 17:51:13 +0000 | [diff] [blame] | 656 | |
Ben Clayton | 053559d | 2021-07-23 16:43:01 +0000 | [diff] [blame] | 657 | // Builtin types starting with a _ prefix cannot be declared in WGSL, so they |
| 658 | // can only be used as return types. Because of this, they must only match Any, |
| 659 | // which is used as the return type matcher. |
| 660 | bool match_modf_result(const sem::Type* ty) { |
| 661 | return ty->Is<Any>(); |
| 662 | } |
| 663 | bool match_modf_result_vec(const sem::Type* ty, Number& N) { |
| 664 | if (!ty->Is<Any>()) { |
| 665 | return false; |
| 666 | } |
| 667 | N = Number::any; |
| 668 | return true; |
| 669 | } |
| 670 | bool match_frexp_result(const sem::Type* ty) { |
| 671 | return ty->Is<Any>(); |
| 672 | } |
| 673 | bool match_frexp_result_vec(const sem::Type* ty, Number& N) { |
| 674 | if (!ty->Is<Any>()) { |
| 675 | return false; |
| 676 | } |
| 677 | N = Number::any; |
| 678 | return true; |
| 679 | } |
| 680 | |
| 681 | struct NameAndType { |
| 682 | std::string name; |
| 683 | sem::Type* type; |
| 684 | }; |
| 685 | const sem::Struct* build_struct( |
| 686 | MatchState& state, |
| 687 | std::string name, |
| 688 | std::initializer_list<NameAndType> member_names_and_types) { |
| 689 | uint32_t offset = 0; |
| 690 | uint32_t max_align = 0; |
| 691 | sem::StructMemberList members; |
| 692 | for (auto& m : member_names_and_types) { |
| 693 | uint32_t align = m.type->Align(); |
| 694 | uint32_t size = m.type->Size(); |
| 695 | offset = utils::RoundUp(align, offset); |
| 696 | max_align = std::max(max_align, align); |
| 697 | members.emplace_back(state.builder.create<sem::StructMember>( |
| 698 | /* declaration */ nullptr, |
| 699 | /* name */ state.builder.Sym(m.name), |
| 700 | /* type */ m.type, |
| 701 | /* index */ static_cast<uint32_t>(members.size()), |
| 702 | /* offset */ offset, |
| 703 | /* align */ align, |
| 704 | /* size */ size)); |
| 705 | offset += size; |
| 706 | } |
| 707 | uint32_t size_without_padding = offset; |
| 708 | uint32_t size_with_padding = utils::RoundUp(max_align, offset); |
| 709 | return state.builder.create<sem::Struct>( |
| 710 | /* declaration */ nullptr, |
| 711 | /* name */ state.builder.Sym(name), |
| 712 | /* members */ members, |
| 713 | /* align */ max_align, |
| 714 | /* size */ size_with_padding, |
| 715 | /* size_no_padding */ size_without_padding); |
| 716 | } |
| 717 | |
| 718 | const sem::Struct* build_modf_result(MatchState& state) { |
| 719 | auto* f32 = state.builder.create<sem::F32>(); |
| 720 | return build_struct(state, "_modf_result", {{"fract", f32}, {"whole", f32}}); |
| 721 | } |
| 722 | const sem::Struct* build_modf_result_vec(MatchState& state, Number& n) { |
| 723 | auto* vec_f32 = state.builder.create<sem::Vector>( |
| 724 | state.builder.create<sem::F32>(), n.Value()); |
| 725 | return build_struct(state, "_modf_result_vec" + std::to_string(n.Value()), |
| 726 | {{"fract", vec_f32}, {"whole", vec_f32}}); |
| 727 | } |
| 728 | const sem::Struct* build_frexp_result(MatchState& state) { |
| 729 | auto* f32 = state.builder.create<sem::F32>(); |
| 730 | auto* i32 = state.builder.create<sem::I32>(); |
| 731 | return build_struct(state, "_frexp_result", {{"sig", f32}, {"exp", i32}}); |
| 732 | } |
| 733 | const sem::Struct* build_frexp_result_vec(MatchState& state, Number& n) { |
| 734 | auto* vec_f32 = state.builder.create<sem::Vector>( |
| 735 | state.builder.create<sem::F32>(), n.Value()); |
| 736 | auto* vec_i32 = state.builder.create<sem::Vector>( |
| 737 | state.builder.create<sem::I32>(), n.Value()); |
| 738 | return build_struct(state, "_frexp_result_vec" + std::to_string(n.Value()), |
| 739 | {{"sig", vec_f32}, {"exp", vec_i32}}); |
| 740 | } |
| 741 | |
Ben Clayton | 71786c9 | 2021-06-03 16:07:34 +0000 | [diff] [blame] | 742 | /// ParameterInfo describes a parameter |
| 743 | struct ParameterInfo { |
| 744 | /// The parameter usage (parameter name in definition file) |
| 745 | ParameterUsage const usage; |
| 746 | |
| 747 | /// Pointer to a list of indices that are used to match the parameter type. |
| 748 | /// The matcher indices index on Matchers::type and / or Matchers::number. |
| 749 | /// These indices are consumed by the matchers themselves. |
| 750 | /// The first index is always a TypeMatcher. |
| 751 | MatcherIndex const* const matcher_indices; |
| 752 | }; |
| 753 | |
| 754 | /// OpenTypeInfo describes an open type |
| 755 | struct OpenTypeInfo { |
| 756 | /// Name of the open type (e.g. 'T') |
| 757 | const char* name; |
| 758 | /// Optional type matcher constraint. |
| 759 | /// Either an index in Matchers::type, or kNoMatcher |
| 760 | MatcherIndex const matcher_index; |
| 761 | }; |
| 762 | |
| 763 | /// OpenNumberInfo describes an open number |
| 764 | struct OpenNumberInfo { |
| 765 | /// Name of the open number (e.g. 'N') |
| 766 | const char* name; |
| 767 | /// Optional number matcher constraint. |
| 768 | /// Either an index in Matchers::number, or kNoMatcher |
| 769 | MatcherIndex const matcher_index; |
| 770 | }; |
| 771 | |
| 772 | /// OverloadInfo describes a single function overload |
| 773 | struct OverloadInfo { |
| 774 | /// Total number of parameters for the overload |
| 775 | uint8_t const num_parameters; |
| 776 | /// Total number of open types for the overload |
| 777 | uint8_t const num_open_types; |
| 778 | /// Total number of open numbers for the overload |
| 779 | uint8_t const num_open_numbers; |
| 780 | /// Pointer to the first open type |
| 781 | OpenTypeInfo const* const open_types; |
| 782 | /// Pointer to the first open number |
| 783 | OpenNumberInfo const* const open_numbers; |
| 784 | /// Pointer to the first parameter |
| 785 | ParameterInfo const* const parameters; |
| 786 | /// Pointer to a list of matcher indices that index on Matchers::type and |
| 787 | /// Matchers::number, used to build the return type. If the function has no |
Ben Clayton | 3e59eb0 | 2021-06-10 17:31:54 +0000 | [diff] [blame] | 788 | /// return type then this is null |
Ben Clayton | 71786c9 | 2021-06-03 16:07:34 +0000 | [diff] [blame] | 789 | MatcherIndex const* const return_matcher_indices; |
Ben Clayton | 3e59eb0 | 2021-06-10 17:31:54 +0000 | [diff] [blame] | 790 | /// The pipeline stages that this overload can be used in |
Ben Clayton | 71786c9 | 2021-06-03 16:07:34 +0000 | [diff] [blame] | 791 | PipelineStageSet supported_stages; |
Ben Clayton | 3e59eb0 | 2021-06-10 17:31:54 +0000 | [diff] [blame] | 792 | /// True if the overload is marked as deprecated |
| 793 | bool is_deprecated; |
Ben Clayton | 71786c9 | 2021-06-03 16:07:34 +0000 | [diff] [blame] | 794 | }; |
| 795 | |
| 796 | /// IntrinsicInfo describes an intrinsic function |
| 797 | struct IntrinsicInfo { |
| 798 | /// Number of overloads of the intrinsic function |
| 799 | uint8_t const num_overloads; |
| 800 | /// Pointer to the start of the overloads for the function |
| 801 | OverloadInfo const* const overloads; |
| 802 | }; |
| 803 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 804 | #include "intrinsic_table.inl" |
Ben Clayton | 06d8db2 | 2021-02-08 22:59:44 +0000 | [diff] [blame] | 805 | |
Ben Clayton | 0f2d95d | 2021-07-22 13:24:59 +0000 | [diff] [blame] | 806 | /// IntrinsicPrototype describes a fully matched intrinsic function, which is |
| 807 | /// used as a lookup for building unique sem::Intrinsic instances. |
| 808 | struct IntrinsicPrototype { |
| 809 | /// Parameter describes a single parameter |
| 810 | struct Parameter { |
| 811 | /// Parameter type |
| 812 | sem::Type* const type; |
| 813 | /// Parameter usage |
| 814 | ParameterUsage const usage = ParameterUsage::kNone; |
| 815 | }; |
| 816 | |
| 817 | /// Hasher provides a hash function for the IntrinsicPrototype |
| 818 | struct Hasher { |
| 819 | /// @param i the IntrinsicPrototype to create a hash for |
| 820 | /// @return the hash value |
| 821 | inline std::size_t operator()(const IntrinsicPrototype& i) const { |
| 822 | size_t hash = utils::Hash(i.parameters.size()); |
| 823 | for (auto& p : i.parameters) { |
| 824 | utils::HashCombine(&hash, p.type, p.usage); |
| 825 | } |
| 826 | return utils::Hash(hash, i.type, i.return_type, i.supported_stages, |
| 827 | i.is_deprecated); |
| 828 | } |
| 829 | }; |
| 830 | |
| 831 | sem::IntrinsicType type = sem::IntrinsicType::kNone; |
| 832 | std::vector<Parameter> parameters; |
| 833 | sem::Type const* return_type = nullptr; |
| 834 | PipelineStageSet supported_stages; |
| 835 | bool is_deprecated = false; |
| 836 | }; |
| 837 | |
| 838 | /// Equality operator for IntrinsicPrototype |
| 839 | bool operator==(const IntrinsicPrototype& a, const IntrinsicPrototype& b) { |
| 840 | if (a.type != b.type || a.supported_stages != b.supported_stages || |
| 841 | a.return_type != b.return_type || a.is_deprecated != b.is_deprecated || |
| 842 | a.parameters.size() != b.parameters.size()) { |
| 843 | return false; |
| 844 | } |
| 845 | for (size_t i = 0; i < a.parameters.size(); i++) { |
| 846 | auto& pa = a.parameters[i]; |
| 847 | auto& pb = b.parameters[i]; |
| 848 | if (pa.type != pb.type || pa.usage != pb.usage) { |
| 849 | return false; |
| 850 | } |
| 851 | } |
| 852 | return true; |
| 853 | } |
| 854 | |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 855 | /// Impl is the private implementation of the IntrinsicTable interface. |
| 856 | class Impl : public IntrinsicTable { |
| 857 | public: |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 858 | explicit Impl(ProgramBuilder& builder); |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 859 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 860 | const sem::Intrinsic* Lookup(sem::IntrinsicType intrinsic_type, |
| 861 | const std::vector<const sem::Type*>& args, |
Ben Clayton | b478f97 | 2021-07-15 20:34:21 +0000 | [diff] [blame] | 862 | const Source& source) override; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 863 | |
| 864 | private: |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 865 | const sem::Intrinsic* Match(sem::IntrinsicType intrinsic_type, |
| 866 | const OverloadInfo& overload, |
| 867 | const std::vector<const sem::Type*>& args, |
Ben Clayton | b478f97 | 2021-07-15 20:34:21 +0000 | [diff] [blame] | 868 | int& match_score); |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 869 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 870 | MatchState Match(ClosedState& closed, |
| 871 | const OverloadInfo& overload, |
| 872 | MatcherIndex const* matcher_indices) const; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 873 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 874 | void PrintOverload(std::ostream& ss, |
| 875 | const OverloadInfo& overload, |
| 876 | sem::IntrinsicType intrinsic_type) const; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 877 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 878 | ProgramBuilder& builder; |
| 879 | Matchers matchers; |
Ben Clayton | 0f2d95d | 2021-07-22 13:24:59 +0000 | [diff] [blame] | 880 | std::unordered_map<IntrinsicPrototype, |
| 881 | sem::Intrinsic*, |
| 882 | IntrinsicPrototype::Hasher> |
| 883 | intrinsics; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 884 | }; |
| 885 | |
Ben Clayton | 6b4924f | 2021-02-17 20:13:34 +0000 | [diff] [blame] | 886 | /// @return a string representing a call to an intrinsic with the given argument |
| 887 | /// types. |
| 888 | std::string CallSignature(ProgramBuilder& builder, |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 889 | sem::IntrinsicType intrinsic_type, |
Ben Clayton | 12ed13d | 2021-04-28 12:38:13 +0000 | [diff] [blame] | 890 | const std::vector<const sem::Type*>& args) { |
Ben Clayton | 6b4924f | 2021-02-17 20:13:34 +0000 | [diff] [blame] | 891 | std::stringstream ss; |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 892 | ss << sem::str(intrinsic_type) << "("; |
Ben Clayton | 6b4924f | 2021-02-17 20:13:34 +0000 | [diff] [blame] | 893 | { |
| 894 | bool first = true; |
| 895 | for (auto* arg : args) { |
| 896 | if (!first) { |
| 897 | ss << ", "; |
| 898 | } |
| 899 | first = false; |
Ben Clayton | 9b54a2e | 2021-05-18 10:28:48 +0000 | [diff] [blame] | 900 | ss << arg->UnwrapRef()->FriendlyName(builder.Symbols()); |
Ben Clayton | 6b4924f | 2021-02-17 20:13:34 +0000 | [diff] [blame] | 901 | } |
| 902 | } |
| 903 | ss << ")"; |
| 904 | |
| 905 | return ss.str(); |
| 906 | } |
| 907 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 908 | std::string OpenTypeMatcher::String(MatchState& state) const { |
| 909 | return state.overload.open_types[index_].name; |
| 910 | } |
| 911 | |
| 912 | std::string OpenNumberMatcher::String(MatchState& state) const { |
| 913 | return state.overload.open_numbers[index_].name; |
| 914 | } |
| 915 | |
| 916 | Impl::Impl(ProgramBuilder& b) : builder(b) {} |
| 917 | |
| 918 | const sem::Intrinsic* Impl::Lookup(sem::IntrinsicType intrinsic_type, |
| 919 | const std::vector<const sem::Type*>& args, |
Ben Clayton | b478f97 | 2021-07-15 20:34:21 +0000 | [diff] [blame] | 920 | const Source& source) { |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 921 | // Candidate holds information about a mismatched overload that could be what |
| 922 | // the user intended to call. |
| 923 | struct Candidate { |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 924 | const OverloadInfo* overload; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 925 | int score; |
| 926 | }; |
| 927 | |
| 928 | // The list of failed matches that had promise. |
| 929 | std::vector<Candidate> candidates; |
| 930 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 931 | auto& intrinsic = kIntrinsics[static_cast<uint32_t>(intrinsic_type)]; |
| 932 | for (uint32_t o = 0; o < intrinsic.num_overloads; o++) { |
| 933 | int match_score = 1000; |
| 934 | auto& overload = intrinsic.overloads[o]; |
| 935 | if (auto* match = Match(intrinsic_type, overload, args, match_score)) { |
| 936 | return match; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 937 | } |
| 938 | if (match_score > 0) { |
| 939 | candidates.emplace_back(Candidate{&overload, match_score}); |
| 940 | } |
| 941 | } |
| 942 | |
| 943 | // Sort the candidates with the most promising first |
| 944 | std::stable_sort( |
| 945 | candidates.begin(), candidates.end(), |
| 946 | [](const Candidate& a, const Candidate& b) { return a.score > b.score; }); |
| 947 | |
| 948 | // Generate an error message |
| 949 | std::stringstream ss; |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 950 | ss << "no matching call to " << CallSignature(builder, intrinsic_type, args) |
Ben Clayton | 6b4924f | 2021-02-17 20:13:34 +0000 | [diff] [blame] | 951 | << std::endl; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 952 | if (!candidates.empty()) { |
| 953 | ss << std::endl; |
| 954 | ss << candidates.size() << " candidate function" |
| 955 | << (candidates.size() > 1 ? "s:" : ":") << std::endl; |
| 956 | for (auto& candidate : candidates) { |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 957 | ss << " "; |
| 958 | PrintOverload(ss, *candidate.overload, intrinsic_type); |
| 959 | ss << std::endl; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 960 | } |
| 961 | } |
Ben Clayton | ffd28e2 | 2021-06-24 11:27:36 +0000 | [diff] [blame] | 962 | builder.Diagnostics().add_error(diag::System::Resolver, ss.str(), source); |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 963 | return nullptr; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 964 | } |
| 965 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 966 | const sem::Intrinsic* Impl::Match(sem::IntrinsicType intrinsic_type, |
| 967 | const OverloadInfo& overload, |
| 968 | const std::vector<const sem::Type*>& args, |
Ben Clayton | b478f97 | 2021-07-15 20:34:21 +0000 | [diff] [blame] | 969 | int& match_score) { |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 970 | // Score wait for argument <-> parameter count matches / mismatches |
| 971 | constexpr int kScorePerParamArgMismatch = -1; |
| 972 | constexpr int kScorePerMatchedParam = 2; |
| 973 | constexpr int kScorePerMatchedOpenType = 1; |
| 974 | constexpr int kScorePerMatchedOpenNumber = 1; |
| 975 | |
| 976 | auto num_parameters = overload.num_parameters; |
| 977 | auto num_arguments = static_cast<decltype(num_parameters)>(args.size()); |
| 978 | |
| 979 | bool overload_matched = true; |
| 980 | |
| 981 | if (num_parameters != num_arguments) { |
| 982 | match_score += |
| 983 | kScorePerParamArgMismatch * (std::max(num_parameters, num_arguments) - |
| 984 | std::min(num_parameters, num_arguments)); |
| 985 | overload_matched = false; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 986 | } |
| 987 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 988 | ClosedState closed(builder); |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 989 | |
Ben Clayton | 0f2d95d | 2021-07-22 13:24:59 +0000 | [diff] [blame] | 990 | std::vector<IntrinsicPrototype::Parameter> parameters; |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 991 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 992 | auto num_params = std::min(num_parameters, num_arguments); |
| 993 | for (uint32_t p = 0; p < num_params; p++) { |
| 994 | auto& parameter = overload.parameters[p]; |
| 995 | auto* indices = parameter.matcher_indices; |
| 996 | auto* type = Match(closed, overload, indices).Type(args[p]->UnwrapRef()); |
| 997 | if (type) { |
Ben Clayton | 0f2d95d | 2021-07-22 13:24:59 +0000 | [diff] [blame] | 998 | parameters.emplace_back(IntrinsicPrototype::Parameter{ |
| 999 | const_cast<sem::Type*>(type), parameter.usage}); |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 1000 | match_score += kScorePerMatchedParam; |
Ben Clayton | faca02d | 2021-02-10 21:34:25 +0000 | [diff] [blame] | 1001 | } else { |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 1002 | overload_matched = false; |
Ben Clayton | faca02d | 2021-02-10 21:34:25 +0000 | [diff] [blame] | 1003 | } |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 1004 | } |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 1005 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 1006 | if (overload_matched) { |
| 1007 | // Check all constrained open types matched |
| 1008 | for (uint32_t ot = 0; ot < overload.num_open_types; ot++) { |
| 1009 | auto& open_type = overload.open_types[ot]; |
| 1010 | if (open_type.matcher_index != kNoMatcher) { |
| 1011 | auto* index = &open_type.matcher_index; |
| 1012 | if (Match(closed, overload, index).Type(closed.Type(ot))) { |
| 1013 | match_score += kScorePerMatchedOpenType; |
| 1014 | } else { |
| 1015 | overload_matched = false; |
| 1016 | } |
| 1017 | } |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 1018 | } |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 1019 | } |
| 1020 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 1021 | if (overload_matched) { |
| 1022 | // Check all constrained open numbers matched |
| 1023 | for (uint32_t on = 0; on < overload.num_open_numbers; on++) { |
| 1024 | auto& open_number = overload.open_numbers[on]; |
| 1025 | if (open_number.matcher_index != kNoMatcher) { |
| 1026 | auto* index = &open_number.matcher_index; |
| 1027 | if (Match(closed, overload, index).Num(closed.Num(on)).IsValid()) { |
| 1028 | match_score += kScorePerMatchedOpenNumber; |
| 1029 | } else { |
| 1030 | overload_matched = false; |
| 1031 | } |
| 1032 | } |
| 1033 | } |
| 1034 | } |
| 1035 | |
| 1036 | if (!overload_matched) { |
| 1037 | return nullptr; |
| 1038 | } |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 1039 | |
| 1040 | // Build the return type |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 1041 | const sem::Type* return_type = nullptr; |
| 1042 | if (auto* indices = overload.return_matcher_indices) { |
| 1043 | Any any; |
| 1044 | return_type = Match(closed, overload, indices).Type(&any); |
| 1045 | if (!return_type) { |
| 1046 | std::stringstream ss; |
| 1047 | PrintOverload(ss, overload, intrinsic_type); |
Ben Clayton | ffd28e2 | 2021-06-24 11:27:36 +0000 | [diff] [blame] | 1048 | TINT_ICE(Resolver, builder.Diagnostics()) |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 1049 | << "MatchState.Match() returned null for " << ss.str(); |
| 1050 | return nullptr; |
| 1051 | } |
| 1052 | } else { |
| 1053 | return_type = builder.create<sem::Void>(); |
Ben Clayton | 90f43cf | 2021-03-31 20:43:26 +0000 | [diff] [blame] | 1054 | } |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 1055 | |
Ben Clayton | 0f2d95d | 2021-07-22 13:24:59 +0000 | [diff] [blame] | 1056 | IntrinsicPrototype intrinsic; |
| 1057 | intrinsic.type = intrinsic_type; |
| 1058 | intrinsic.return_type = return_type; |
| 1059 | intrinsic.parameters = std::move(parameters); |
| 1060 | intrinsic.supported_stages = overload.supported_stages; |
| 1061 | intrinsic.is_deprecated = overload.is_deprecated; |
Ben Clayton | b478f97 | 2021-07-15 20:34:21 +0000 | [diff] [blame] | 1062 | |
| 1063 | // De-duplicate intrinsics that are identical. |
| 1064 | return utils::GetOrCreate(intrinsics, intrinsic, [&] { |
Ben Clayton | 4ffcf06 | 2021-07-22 13:24:59 +0000 | [diff] [blame] | 1065 | std::vector<sem::Parameter*> params; |
Ben Clayton | 0f2d95d | 2021-07-22 13:24:59 +0000 | [diff] [blame] | 1066 | params.reserve(intrinsic.parameters.size()); |
| 1067 | for (auto& p : intrinsic.parameters) { |
| 1068 | params.emplace_back(builder.create<sem::Parameter>( |
Ben Clayton | 4ffcf06 | 2021-07-22 13:24:59 +0000 | [diff] [blame] | 1069 | nullptr, static_cast<uint32_t>(params.size()), p.type, |
| 1070 | ast::StorageClass::kNone, ast::Access::kUndefined, p.usage)); |
Ben Clayton | 0f2d95d | 2021-07-22 13:24:59 +0000 | [diff] [blame] | 1071 | } |
| 1072 | return builder.create<sem::Intrinsic>( |
| 1073 | intrinsic.type, const_cast<sem::Type*>(intrinsic.return_type), |
| 1074 | std::move(params), intrinsic.supported_stages, intrinsic.is_deprecated); |
Ben Clayton | b478f97 | 2021-07-15 20:34:21 +0000 | [diff] [blame] | 1075 | }); |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 1076 | } |
| 1077 | |
| 1078 | MatchState Impl::Match(ClosedState& closed, |
| 1079 | const OverloadInfo& overload, |
| 1080 | MatcherIndex const* matcher_indices) const { |
| 1081 | return MatchState(builder, closed, matchers, overload, matcher_indices); |
| 1082 | } |
| 1083 | |
| 1084 | void Impl::PrintOverload(std::ostream& ss, |
| 1085 | const OverloadInfo& overload, |
| 1086 | sem::IntrinsicType intrinsic_type) const { |
| 1087 | ClosedState closed(builder); |
| 1088 | |
| 1089 | ss << intrinsic_type << "("; |
| 1090 | for (uint32_t p = 0; p < overload.num_parameters; p++) { |
| 1091 | auto& parameter = overload.parameters[p]; |
| 1092 | if (p > 0) { |
| 1093 | ss << ", "; |
| 1094 | } |
| 1095 | if (parameter.usage != ParameterUsage::kNone) { |
| 1096 | ss << sem::str(parameter.usage) << ": "; |
| 1097 | } |
| 1098 | auto* indices = parameter.matcher_indices; |
| 1099 | ss << Match(closed, overload, indices).TypeName(); |
| 1100 | } |
| 1101 | ss << ")"; |
| 1102 | if (overload.return_matcher_indices) { |
| 1103 | ss << " -> "; |
| 1104 | auto* indices = overload.return_matcher_indices; |
| 1105 | ss << Match(closed, overload, indices).TypeName(); |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 1106 | } |
| 1107 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 1108 | bool first = true; |
| 1109 | auto separator = [&] { |
| 1110 | ss << (first ? " where: " : ", "); |
| 1111 | first = false; |
| 1112 | }; |
| 1113 | for (uint32_t i = 0; i < overload.num_open_types; i++) { |
| 1114 | auto& open_type = overload.open_types[i]; |
| 1115 | if (open_type.matcher_index != kNoMatcher) { |
| 1116 | separator(); |
| 1117 | ss << open_type.name; |
| 1118 | auto* index = &open_type.matcher_index; |
| 1119 | ss << " is " << Match(closed, overload, index).TypeName(); |
| 1120 | } |
| 1121 | } |
| 1122 | for (uint32_t i = 0; i < overload.num_open_numbers; i++) { |
| 1123 | auto& open_number = overload.open_numbers[i]; |
| 1124 | if (open_number.matcher_index != kNoMatcher) { |
| 1125 | separator(); |
| 1126 | ss << open_number.name; |
| 1127 | auto* index = &open_number.matcher_index; |
| 1128 | ss << " is " << Match(closed, overload, index).NumName(); |
| 1129 | } |
| 1130 | } |
| 1131 | } |
| 1132 | |
| 1133 | const sem::Type* MatchState::Type(const sem::Type* ty) { |
| 1134 | MatcherIndex matcher_index = *matcher_indices_++; |
| 1135 | auto* matcher = matchers.type[matcher_index]; |
| 1136 | return matcher->Match(*this, ty); |
| 1137 | } |
| 1138 | |
| 1139 | Number MatchState::Num(Number number) { |
| 1140 | MatcherIndex matcher_index = *matcher_indices_++; |
| 1141 | auto* matcher = matchers.number[matcher_index]; |
| 1142 | return matcher->Match(*this, number); |
| 1143 | } |
| 1144 | |
| 1145 | std::string MatchState::TypeName() { |
| 1146 | MatcherIndex matcher_index = *matcher_indices_++; |
| 1147 | auto* matcher = matchers.type[matcher_index]; |
| 1148 | return matcher->String(*this); |
| 1149 | } |
| 1150 | |
| 1151 | std::string MatchState::NumName() { |
| 1152 | MatcherIndex matcher_index = *matcher_indices_++; |
| 1153 | auto* matcher = matchers.number[matcher_index]; |
| 1154 | return matcher->String(*this); |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 1155 | } |
| 1156 | |
| 1157 | } // namespace |
| 1158 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 1159 | std::unique_ptr<IntrinsicTable> IntrinsicTable::Create( |
| 1160 | ProgramBuilder& builder) { |
| 1161 | return std::make_unique<Impl>(builder); |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 1162 | } |
| 1163 | |
| 1164 | IntrinsicTable::~IntrinsicTable() = default; |
| 1165 | |
Ben Clayton | b29a59d | 2021-06-01 19:06:31 +0000 | [diff] [blame] | 1166 | /// TypeInfo for the Any type declared in the anonymous namespace above |
| 1167 | TINT_INSTANTIATE_TYPEINFO(Any); |
| 1168 | |
Ben Clayton | 59d2473 | 2021-02-08 22:42:54 +0000 | [diff] [blame] | 1169 | } // namespace tint |