Branch data Line data Source code
1 : : #pragma once
2 : :
3 : : #include "backend/WasmUtil.hpp"
4 : : #include <mutable/IR/PhysicalOptimizer.hpp>
5 : : #include <mutable/storage/DataLayoutFactory.hpp>
6 : : #include <mutable/util/enum_ops.hpp>
7 : :
8 : :
9 : : namespace m {
10 : :
11 : : namespace wasm {
12 : :
13 : : // forward declarations
14 : : struct MatchBaseVisitor;
15 : : struct ConstMatchBaseVisitor;
16 : :
17 : : }
18 : :
19 : : namespace option_configs {
20 : :
21 : : /*----- algorithmic decisions ----------------------------------------------------------------------------------------*/
22 : : enum class ScanImplementation : uint64_t {
23 : : ALL = 0b11,
24 : : SCAN = 0b01,
25 : : INDEX_SCAN = 0b10,
26 : : };
27 : :
28 : : enum class GroupingImplementation : uint64_t {
29 : : ALL = 0b11,
30 : : HASH_BASED = 0b01,
31 : : ORDERED = 0b10,
32 : : };
33 : :
34 : : enum class SortingImplementation : uint64_t {
35 : : ALL = 0b11,
36 : : QUICKSORT = 0b01,
37 : : NOOP = 0b10,
38 : : };
39 : :
40 : : enum class JoinImplementation : uint64_t {
41 : : ALL = 0b111,
42 : : NESTED_LOOPS = 0b001,
43 : : SIMPLE_HASH = 0b010,
44 : : SORT_MERGE = 0b100,
45 : : };
46 : :
47 : : enum class IndexImplementation : uint64_t {
48 : : ALL = 0b11,
49 : : ARRAY = 0b01,
50 : : RMI = 0b10,
51 : : };
52 : :
53 : : enum class SoftPipelineBreakerStrategy : uint64_t {
54 : : AFTER_ALL = 0b1111111,
55 : : AFTER_SCAN = 0b0000001,
56 : : AFTER_FILTER = 0b0000010,
57 : : AFTER_INDEX_SCAN = 0b0000100,
58 : : AFTER_PROJECTION = 0b0001000,
59 : : AFTER_NESTED_LOOPS_JOIN = 0b0010000,
60 : : AFTER_SIMPLE_HASH_JOIN = 0b0100000,
61 : : AFTER_HASH_BASED_GROUP_JOIN = 0b1000000,
62 : : NONE = 0b0000000,
63 : : };
64 : :
65 : : /*----- implementation decisions -------------------------------------------------------------------------------------*/
66 : : enum class IndexScanStrategy : uint64_t {
67 : : COMPILATION = 0b001,
68 : : INTERPRETATION = 0b010,
69 : : HYBRID = 0b100,
70 : : };
71 : :
72 : : enum class IndexScanCompilationStrategy : uint64_t {
73 : : CALLBACK = 0b01,
74 : : EXPOSED_MEMORY = 0b10,
75 : : };
76 : :
77 : : enum class IndexScanMaterializationStrategy : uint64_t {
78 : : INLINE = 0b01,
79 : : MEMORY = 0b10,
80 : : };
81 : :
82 : : enum class SelectionStrategy : uint64_t {
83 : : AUTO = 0b11,
84 : : BRANCHING = 0b01,
85 : : PREDICATED = 0b10,
86 : : };
87 : :
88 : : enum class HashTableImplementation : uint64_t {
89 : : ALL = 0b11,
90 : : OPEN_ADDRESSING = 0b01,
91 : : CHAINED = 0b10,
92 : : };
93 : :
94 : : enum class ProbingStrategy : uint64_t {
95 : : AUTO = 0b11,
96 : : LINEAR = 0b01,
97 : : QUADRATIC = 0b10,
98 : : };
99 : :
100 : : enum class StoringStrategy : uint64_t {
101 : : AUTO = 0b11,
102 : : IN_PLACE = 0b01,
103 : : OUT_OF_PLACE = 0b10,
104 : : };
105 : :
106 : : enum class OrderingStrategy : uint64_t {
107 : : AUTO = 0b11,
108 : : BUILD_ON_LEFT = 0b01,
109 : : BUILD_ON_RIGHT = 0b10,
110 : : };
111 : :
112 : : }
113 : :
114 : : namespace options {
115 : :
116 : : /*----- options ------------------------------------------------------------------------------------------------------*/
117 : : /** Which implementations should be considered for a `ScanOperator`. */
118 : : inline option_configs::ScanImplementation scan_implementations = option_configs::ScanImplementation::ALL;
119 : :
120 : : /** Which implementations should be considered for a `GroupingOperator`. */
121 : : inline option_configs::GroupingImplementation grouping_implementations = option_configs::GroupingImplementation::ALL;
122 : :
123 : : /** Which implementations should be considered for a `SortingOperator`. */
124 : : inline option_configs::SortingImplementation sorting_implementations = option_configs::SortingImplementation::ALL;
125 : :
126 : : /** Which implementations should be considered for a `JoinOperator`. */
127 : : inline option_configs::JoinImplementation join_implementations = option_configs::JoinImplementation::ALL;
128 : :
129 : : /** Which index implementations should be considered for an `IndexScan`. */
130 : : inline option_configs::IndexImplementation index_implementations = option_configs::IndexImplementation::ALL;
131 : :
132 : : /** Which index scan strategy should be used for `wasm::IndexScan`. */
133 : : inline option_configs::IndexScanStrategy index_scan_strategy = option_configs::IndexScanStrategy::INTERPRETATION;
134 : :
135 : : /** Which compilation strategy should be used for `wasm::IndexScan`. */
136 : : inline option_configs::IndexScanCompilationStrategy index_scan_compilation_strategy =
137 : : option_configs::IndexScanCompilationStrategy::CALLBACK;
138 : :
139 : : /** Which materialization strategy should be used for `wasm::IndexScan`. */
140 : : inline option_configs::IndexScanMaterializationStrategy index_scan_materialization_strategy =
141 : : option_configs::IndexScanMaterializationStrategy::MEMORY;
142 : :
143 : : /** Which selection strategy should be used for `wasm::Filter`. */
144 : : inline option_configs::SelectionStrategy filter_selection_strategy = option_configs::SelectionStrategy::AUTO;
145 : :
146 : : /** Which selection strategy should be used for comparisons in `wasm::Quicksort`. */
147 : : inline option_configs::SelectionStrategy quicksort_cmp_selection_strategy = option_configs::SelectionStrategy::AUTO;
148 : :
149 : : /** Which selection strategy should be used for `wasm::NestedLoopsJoin`. */
150 : : inline option_configs::SelectionStrategy nested_loops_join_selection_strategy = option_configs::SelectionStrategy::AUTO;
151 : :
152 : : /** Which selection strategy should be used for `wasm::SimpleHashJoin`. */
153 : : inline option_configs::SelectionStrategy simple_hash_join_selection_strategy = option_configs::SelectionStrategy::AUTO;
154 : :
155 : : /** Which ordering strategy should be used for `wasm::SimpleHashJoin`. */
156 : : inline option_configs::OrderingStrategy simple_hash_join_ordering_strategy = option_configs::OrderingStrategy::AUTO;
157 : :
158 : : /** Which selection strategy should be used for `wasm::SortMergeJoin`. */
159 : : inline option_configs::SelectionStrategy sort_merge_join_selection_strategy = option_configs::SelectionStrategy::AUTO;
160 : :
161 : : /** Which selection strategy should be used for comparisons while sorting in `wasm::SortMergeJoin`. */
162 : : inline option_configs::SelectionStrategy sort_merge_join_cmp_selection_strategy =
163 : : option_configs::SelectionStrategy::AUTO;
164 : :
165 : : /** Which implementation should be used for `wasm::HashTable`s. */
166 : : inline option_configs::HashTableImplementation hash_table_implementation = option_configs::HashTableImplementation::ALL;
167 : :
168 : : /** Which probing strategy should be used for `wasm::OpenAddressingHashTable`s. Does not have any effect if
169 : : * `wasm::ChainedHashTable`s are used. */
170 : : inline option_configs::ProbingStrategy hash_table_probing_strategy = option_configs::ProbingStrategy::AUTO;
171 : :
172 : : /** Which storing strategy should be used for `wasm::OpenAddressingHashTable`s. Does not have any effect if
173 : : * `wasm::ChainedHashTable`s are used. */
174 : : inline option_configs::StoringStrategy hash_table_storing_strategy = option_configs::StoringStrategy::AUTO;
175 : :
176 : : /** Which maximal load factor should be used for `wasm::OpenAddressingHashTable`s. Does not have any effect if
177 : : * `wasm::ChainedHashTable`s are used. */
178 : : inline double load_factor_open_addressing = 0.8;
179 : :
180 : : /** Which maximal load factor should be used for `wasm::ChainedHashTable`s. Does not have any effect if
181 : : * `wasm::OpenAddressingHashTable`s are used. */
182 : : inline double load_factor_chained = 1.5;
183 : :
184 : : /** Which initial capacity should be used for `wasm::HashTable`s. */
185 : : inline std::optional<uint32_t> hash_table_initial_capacity;
186 : :
187 : : /** Whether to use `wasm::HashBasedGroupJoin` if possible. */
188 : : inline bool hash_based_group_join = true;
189 : :
190 : : /** Which layout factory should be used for hard pipeline breakers. */
191 : : inline std::unique_ptr<const m::storage::DataLayoutFactory> hard_pipeline_breaker_layout =
192 : : std::make_unique<storage::RowLayoutFactory>();
193 : :
194 : : /** Where soft pipeline breakers should be added. */
195 : : inline option_configs::SoftPipelineBreakerStrategy soft_pipeline_breaker =
196 : : option_configs::SoftPipelineBreakerStrategy::NONE;
197 : :
198 : : /** Which layout factory should be used for soft pipeline breakers. */
199 : : inline std::unique_ptr<const m::storage::DataLayoutFactory> soft_pipeline_breaker_layout =
200 : : std::make_unique<storage::RowLayoutFactory>();
201 : :
202 : : /** Which size in tuples should be used for soft pipeline breakers. */
203 : : inline std::size_t soft_pipeline_breaker_num_tuples = 0;
204 : :
205 : : /** The number of results from index sequential scan to be communicated between host and v8 per batch. 0 means that
206 : : * all results are communicated in a single batch. */
207 : : inline std::size_t index_sequential_scan_batch_size = 1;
208 : :
209 : : /** Which window size should be used for the result set. */
210 : : inline std::size_t result_set_window_size = 0;
211 : :
212 : : /** Whether to exploit uniqueness of build key in hash joins. */
213 : : inline bool exploit_unique_build = true;
214 : :
215 : : /** Whether to use SIMDfication. */
216 : : inline bool simd = true;
217 : :
218 : : /** Whether to use double pumping if SIMDfication is enabled. */
219 : : inline bool double_pumping = true;
220 : :
221 : : /** Which number of SIMD lanes to prefer. */
222 : : inline std::size_t simd_lanes = 1;
223 : :
224 : : /** Which attributes are assumed to be sorted. For each entry, the first element is the name of the attribute and the
225 : : * second one is `true` iff the attribute is sorted ascending and vice versa. */
226 : : inline std::vector<std::pair<m::Schema::Identifier, bool>> sorted_attributes;
227 : :
228 : : }
229 : :
230 : : }
231 : :
232 : : namespace m {
233 : :
234 : : #define M_WASM_OPERATOR_LIST_NON_TEMPLATED(X) \
235 : : X(NoOp) \
236 : : X(LazyDisjunctiveFilter) \
237 : : X(Projection) \
238 : : X(HashBasedGrouping) \
239 : : X(OrderedGrouping) \
240 : : X(Aggregation) \
241 : : X(NoOpSorting) \
242 : : X(Limit) \
243 : : X(HashBasedGroupJoin)
244 : : #define M_WASM_OPERATOR_LIST_TEMPLATED(X) \
245 : : X(Callback<false>) \
246 : : X(Callback<true>) \
247 : : X(Print<false>) \
248 : : X(Print<true>) \
249 : : X(Scan<false>) \
250 : : X(Scan<true>) \
251 : : X(IndexScan<m::idx::IndexMethod::Array>) \
252 : : X(IndexScan<m::idx::IndexMethod::Rmi>) \
253 : : X(Filter<false>) \
254 : : X(Filter<true>) \
255 : : X(Quicksort<false>) \
256 : : X(Quicksort<true>) \
257 : : X(NestedLoopsJoin<false>) \
258 : : X(NestedLoopsJoin<true>) \
259 : : X(SimpleHashJoin<M_COMMA(false) false>) \
260 : : X(SimpleHashJoin<M_COMMA(false) true>) \
261 : : X(SimpleHashJoin<M_COMMA(true) false>) \
262 : : X(SimpleHashJoin<M_COMMA(true) true>) \
263 : : X(SortMergeJoin<M_COMMA(false) M_COMMA(false) M_COMMA(false) false>) \
264 : : X(SortMergeJoin<M_COMMA(false) M_COMMA(false) M_COMMA(false) true>) \
265 : : X(SortMergeJoin<M_COMMA(false) M_COMMA(false) M_COMMA(true) false>) \
266 : : X(SortMergeJoin<M_COMMA(false) M_COMMA(false) M_COMMA(true) true>) \
267 : : X(SortMergeJoin<M_COMMA(false) M_COMMA(true) M_COMMA(false) false>) \
268 : : X(SortMergeJoin<M_COMMA(false) M_COMMA(true) M_COMMA(false) true>) \
269 : : X(SortMergeJoin<M_COMMA(false) M_COMMA(true) M_COMMA(true) false>) \
270 : : X(SortMergeJoin<M_COMMA(false) M_COMMA(true) M_COMMA(true) true>) \
271 : : X(SortMergeJoin<M_COMMA(true) M_COMMA(false) M_COMMA(false) false>) \
272 : : X(SortMergeJoin<M_COMMA(true) M_COMMA(false) M_COMMA(false) true>) \
273 : : X(SortMergeJoin<M_COMMA(true) M_COMMA(false) M_COMMA(true) false>) \
274 : : X(SortMergeJoin<M_COMMA(true) M_COMMA(false) M_COMMA(true) true>) \
275 : : X(SortMergeJoin<M_COMMA(true) M_COMMA(true) M_COMMA(false) false>) \
276 : : X(SortMergeJoin<M_COMMA(true) M_COMMA(true) M_COMMA(false) true>) \
277 : : X(SortMergeJoin<M_COMMA(true) M_COMMA(true) M_COMMA(true) false>) \
278 : : X(SortMergeJoin<M_COMMA(true) M_COMMA(true) M_COMMA(true) true>)
279 : : #define M_WASM_OPERATOR_LIST(X) \
280 : : M_WASM_OPERATOR_LIST_NON_TEMPLATED(X) \
281 : : M_WASM_OPERATOR_LIST_TEMPLATED(X)
282 : :
283 : :
284 : : #define MAKE_WASM_MATCH_(OP) m::Match<m::wasm::OP>
285 : : #define M_WASM_MATCH_LIST_NON_TEMPLATED(X) M_TRANSFORM_X_MACRO(X, M_WASM_OPERATOR_LIST_NON_TEMPLATED, MAKE_WASM_MATCH_)
286 : : #define M_WASM_MATCH_LIST_TEMPLATED(X) \
287 : : X(m::Match<m::wasm::Callback<false>>) \
288 : : X(m::Match<m::wasm::Callback<true>>) \
289 : : X(m::Match<m::wasm::Print<false>>) \
290 : : X(m::Match<m::wasm::Print<true>>) \
291 : : X(m::Match<m::wasm::Scan<false>>) \
292 : : X(m::Match<m::wasm::Scan<true>>) \
293 : : X(m::Match<m::wasm::IndexScan<m::idx::IndexMethod::Array>>) \
294 : : X(m::Match<m::wasm::IndexScan<m::idx::IndexMethod::Rmi>>) \
295 : : X(m::Match<m::wasm::Filter<false>>) \
296 : : X(m::Match<m::wasm::Filter<true>>) \
297 : : X(m::Match<m::wasm::Quicksort<false>>) \
298 : : X(m::Match<m::wasm::Quicksort<true>>) \
299 : : X(m::Match<m::wasm::NestedLoopsJoin<false>>) \
300 : : X(m::Match<m::wasm::NestedLoopsJoin<true>>) \
301 : : X(m::Match<m::wasm::SimpleHashJoin<M_COMMA(false) false>>) \
302 : : X(m::Match<m::wasm::SimpleHashJoin<M_COMMA(false) true>>) \
303 : : X(m::Match<m::wasm::SimpleHashJoin<M_COMMA(true) false>>) \
304 : : X(m::Match<m::wasm::SimpleHashJoin<M_COMMA(true) true>>) \
305 : : X(m::Match<m::wasm::SortMergeJoin<M_COMMA(false) M_COMMA(false) M_COMMA(false) false>>) \
306 : : X(m::Match<m::wasm::SortMergeJoin<M_COMMA(false) M_COMMA(false) M_COMMA(false) true>>) \
307 : : X(m::Match<m::wasm::SortMergeJoin<M_COMMA(false) M_COMMA(false) M_COMMA(true) false>>) \
308 : : X(m::Match<m::wasm::SortMergeJoin<M_COMMA(false) M_COMMA(false) M_COMMA(true) true>>) \
309 : : X(m::Match<m::wasm::SortMergeJoin<M_COMMA(false) M_COMMA(true) M_COMMA(false) false>>) \
310 : : X(m::Match<m::wasm::SortMergeJoin<M_COMMA(false) M_COMMA(true) M_COMMA(false) true>>) \
311 : : X(m::Match<m::wasm::SortMergeJoin<M_COMMA(false) M_COMMA(true) M_COMMA(true) false>>) \
312 : : X(m::Match<m::wasm::SortMergeJoin<M_COMMA(false) M_COMMA(true) M_COMMA(true) true>>) \
313 : : X(m::Match<m::wasm::SortMergeJoin<M_COMMA(true) M_COMMA(false) M_COMMA(false) false>>) \
314 : : X(m::Match<m::wasm::SortMergeJoin<M_COMMA(true) M_COMMA(false) M_COMMA(false) true>>) \
315 : : X(m::Match<m::wasm::SortMergeJoin<M_COMMA(true) M_COMMA(false) M_COMMA(true) false>>) \
316 : : X(m::Match<m::wasm::SortMergeJoin<M_COMMA(true) M_COMMA(false) M_COMMA(true) true>>) \
317 : : X(m::Match<m::wasm::SortMergeJoin<M_COMMA(true) M_COMMA(true) M_COMMA(false) false>>) \
318 : : X(m::Match<m::wasm::SortMergeJoin<M_COMMA(true) M_COMMA(true) M_COMMA(false) true>>) \
319 : : X(m::Match<m::wasm::SortMergeJoin<M_COMMA(true) M_COMMA(true) M_COMMA(true) false>>) \
320 : : X(m::Match<m::wasm::SortMergeJoin<M_COMMA(true) M_COMMA(true) M_COMMA(true) true>>)
321 : : #define M_WASM_MATCH_LIST(X) \
322 : : M_WASM_MATCH_LIST_NON_TEMPLATED(X) \
323 : : M_WASM_MATCH_LIST_TEMPLATED(X)
324 : :
325 : : // forward declarations
326 : : #define DECLARE(OP) \
327 : : namespace wasm { struct OP; } \
328 : : template<> struct Match<wasm::OP>;
329 : : M_WASM_OPERATOR_LIST_NON_TEMPLATED(DECLARE)
330 : : #undef DECLARE
331 : :
332 : : namespace wasm { template<bool SIMDfied> struct Callback; }
333 : : template<bool SIMDfied> struct Match<wasm::Callback<SIMDfied>>;
334 : :
335 : : namespace wasm { template<bool SIMDfied> struct Print; }
336 : : template<bool SIMDfied> struct Match<wasm::Print<SIMDfied>>;
337 : :
338 : : namespace wasm { template<bool SIMDfied> struct Scan; }
339 : : template<bool SIMDfied> struct Match<wasm::Scan<SIMDfied>>;
340 : :
341 : : namespace wasm { template<idx::IndexMethod IndexMethod> struct IndexScan; }
342 : : template<idx::IndexMethod IndexMethod> struct Match<wasm::IndexScan<IndexMethod>>;
343 : :
344 : : namespace wasm { template<bool Predicated> struct Filter; }
345 : : template<bool Predicated> struct Match<wasm::Filter<Predicated>>;
346 : :
347 : : namespace wasm { template<bool CmpPredicated> struct Quicksort; }
348 : : template<bool CmpPredicated> struct Match<wasm::Quicksort<CmpPredicated>>;
349 : :
350 : : namespace wasm { template<bool Predicated> struct NestedLoopsJoin; }
351 : : template<bool Predicated> struct Match<wasm::NestedLoopsJoin<Predicated>>;
352 : :
353 : : namespace wasm { template<bool UniqueBuild, bool Predicated> struct SimpleHashJoin; }
354 : : template<bool UniqueBuild, bool Predicated> struct Match<wasm::SimpleHashJoin<UniqueBuild, Predicated>>;
355 : :
356 : : namespace wasm { template<bool SortLeft, bool SortRight, bool Predicated, bool CmpPredicated> struct SortMergeJoin; }
357 : : template<bool SortLeft, bool SortRight, bool Predicated, bool CmpPredicated>
358 : : struct Match<wasm::SortMergeJoin<SortLeft, SortRight, Predicated, CmpPredicated>>;
359 : :
360 : :
361 : : namespace wasm {
362 : :
363 : : struct NoOp : PhysicalOperator<NoOp, NoOpOperator>
364 : : {
365 : : static void execute(const Match<NoOp> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
366 : 0 : static double cost(const Match<NoOp>&) { return 1.0; }
367 : : };
368 : :
369 : : template<bool SIMDfied>
370 : : struct Callback : PhysicalOperator<Callback<SIMDfied>, CallbackOperator>
371 : : {
372 : : static void execute(const Match<Callback> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
373 : 0 : static double cost(const Match<Callback>&) { return 1.0; }
374 : : static ConditionSet pre_condition(std::size_t child_idx,
375 : : const std::tuple<const CallbackOperator*> &partial_inner_nodes);
376 : : };
377 : :
378 : : template<bool SIMDfied>
379 : : struct Print : PhysicalOperator<Print<SIMDfied>, PrintOperator>
380 : : {
381 : : static void execute(const Match<Print> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
382 : 0 : static double cost(const Match<Print>&) { return 1.0; }
383 : : static ConditionSet pre_condition(std::size_t child_idx,
384 : : const std::tuple<const PrintOperator*> &partial_inner_nodes);
385 : : };
386 : :
387 : : template<bool SIMDfied>
388 : : struct Scan : PhysicalOperator<Scan<SIMDfied>, ScanOperator>
389 : : {
390 : : static void execute(const Match<Scan> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
391 : 0 : static double cost(const Match<Scan>&) { return M_CONSTEXPR_COND(SIMDfied, 1.0, 2.0); }
392 : : static ConditionSet pre_condition(std::size_t child_idx,
393 : : const std::tuple<const ScanOperator*> &partial_inner_nodes);
394 : : static ConditionSet post_condition(const Match<Scan> &M);
395 : : };
396 : :
397 : : template<idx::IndexMethod IndexMethod>
398 : : struct IndexScan : PhysicalOperator<IndexScan<IndexMethod>, pattern_t<FilterOperator, ScanOperator>>
399 : : {
400 : : static void execute(const Match<IndexScan> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
401 : : static double cost(const Match<IndexScan> &M);
402 : : static ConditionSet pre_condition(std::size_t child_idx,
403 : : const std::tuple<const FilterOperator*, const ScanOperator*> &partial_inner_nodes);
404 : : static ConditionSet post_condition(const Match<IndexScan> &M);
405 : : };
406 : :
407 : : template<bool Predicated>
408 : : struct Filter : PhysicalOperator<Filter<Predicated>, FilterOperator>
409 : : {
410 : : static void execute(const Match<Filter> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
411 : : static double cost(const Match<Filter>&);
412 : : static ConditionSet pre_condition(std::size_t child_idx,
413 : : const std::tuple<const FilterOperator*> &partial_inner_nodes);
414 : : static ConditionSet adapt_post_condition(const Match<Filter> &M, const ConditionSet &post_cond_child);
415 : : };
416 : :
417 : : struct LazyDisjunctiveFilter : PhysicalOperator<LazyDisjunctiveFilter, DisjunctiveFilterOperator>
418 : : {
419 : : static void execute(const Match<LazyDisjunctiveFilter> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
420 : : static double cost(const Match<LazyDisjunctiveFilter> &M);
421 : : static ConditionSet pre_condition(std::size_t child_idx,
422 : : const std::tuple<const FilterOperator*> &partial_inner_nodes);
423 : : };
424 : :
425 : : struct Projection : PhysicalOperator<Projection, ProjectionOperator>
426 : : {
427 : : static void execute(const Match<Projection> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
428 : 0 : static double cost(const Match<Projection>&) { return 1.0; }
429 : : static ConditionSet pre_condition(std::size_t child_idx,
430 : : const std::tuple<const ProjectionOperator*> &partial_inner_nodes);
431 : : static ConditionSet adapt_post_condition(const Match<Projection> &M, const ConditionSet &post_cond_child);
432 : : };
433 : :
434 : : struct HashBasedGrouping : PhysicalOperator<HashBasedGrouping, GroupingOperator>
435 : : {
436 : : static void execute(const Match<HashBasedGrouping> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
437 : : static double cost(const Match<HashBasedGrouping>&);
438 : : static ConditionSet pre_condition(std::size_t child_idx,
439 : : const std::tuple<const GroupingOperator*> &partial_inner_nodes);
440 : : static ConditionSet post_condition(const Match<HashBasedGrouping> &M);
441 : : };
442 : :
443 : : struct OrderedGrouping : PhysicalOperator<OrderedGrouping, GroupingOperator>
444 : : {
445 : : private:
446 : : template<bool IsGlobal, typename T>
447 : : using var_t_ = std::conditional_t<IsGlobal, Global<T>, Var<T>>;
448 : : template<bool IsGlobal>
449 : : using agg_t_ = std::variant<
450 : : var_t_<IsGlobal, I64x1>,
451 : : std::pair<var_t_<IsGlobal, I8x1>, std::optional<var_t_<IsGlobal, Boolx1>>>,
452 : : std::pair<var_t_<IsGlobal, I16x1>, std::optional<var_t_<IsGlobal, Boolx1>>>,
453 : : std::pair<var_t_<IsGlobal, I32x1>, std::optional<var_t_<IsGlobal, Boolx1>>>,
454 : : std::pair<var_t_<IsGlobal, I64x1>, std::optional<var_t_<IsGlobal, Boolx1>>>,
455 : : std::pair<var_t_<IsGlobal, Floatx1>, std::optional<var_t_<IsGlobal, Boolx1>>>,
456 : : std::pair<var_t_<IsGlobal, Doublex1>, std::optional<var_t_<IsGlobal, Boolx1>>>
457 : : >;
458 : : template<bool IsGlobal>
459 : : using key_t_ = std::variant<
460 : : var_t_<IsGlobal, Ptr<Charx1>>,
461 : : std::pair<var_t_<IsGlobal, Boolx1>, std::optional<var_t_<IsGlobal, Boolx1>>>,
462 : : std::pair<var_t_<IsGlobal, I8x1>, std::optional<var_t_<IsGlobal, Boolx1>>>,
463 : : std::pair<var_t_<IsGlobal, I16x1>, std::optional<var_t_<IsGlobal, Boolx1>>>,
464 : : std::pair<var_t_<IsGlobal, I32x1>, std::optional<var_t_<IsGlobal, Boolx1>>>,
465 : : std::pair<var_t_<IsGlobal, I64x1>, std::optional<var_t_<IsGlobal, Boolx1>>>,
466 : : std::pair<var_t_<IsGlobal, Floatx1>, std::optional<var_t_<IsGlobal, Boolx1>>>,
467 : : std::pair<var_t_<IsGlobal, Doublex1>, std::optional<var_t_<IsGlobal, Boolx1>>>
468 : : >;
469 : :
470 : : public:
471 : : static void execute(const Match<OrderedGrouping> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
472 : : static double cost(const Match<OrderedGrouping>&);
473 : : static ConditionSet pre_condition(std::size_t child_idx,
474 : : const std::tuple<const GroupingOperator*> &partial_inner_nodes);
475 : : static ConditionSet adapt_post_condition(const Match<OrderedGrouping> &M, const ConditionSet &post_cond_child);
476 : : };
477 : :
478 : : struct Aggregation : PhysicalOperator<Aggregation, AggregationOperator>
479 : : {
480 : : private:
481 : : template<bool IsGlobal, typename T>
482 : : using var_t_ = std::conditional_t<IsGlobal, Global<T>, Var<T>>;
483 : : template<bool IsGlobal, std::size_t L>
484 : : using agg_t_ = std::variant<
485 : : var_t_<IsGlobal, I64<L>>,
486 : : std::pair<var_t_<IsGlobal, I8<L>>, var_t_<IsGlobal, Bool<L>>>,
487 : : std::pair<var_t_<IsGlobal, I16<L>>, var_t_<IsGlobal, Bool<L>>>,
488 : : std::pair<var_t_<IsGlobal, I32<L>>, var_t_<IsGlobal, Bool<L>>>,
489 : : std::pair<var_t_<IsGlobal, I64<L>>, var_t_<IsGlobal, Bool<L>>>,
490 : : std::pair<var_t_<IsGlobal, Float<L>>, var_t_<IsGlobal, Bool<L>>>,
491 : : std::pair<var_t_<IsGlobal, Double<L>>, var_t_<IsGlobal, Bool<L>>>
492 : : >;
493 : :
494 : : public:
495 : : static void execute(const Match<Aggregation> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
496 : 0 : static double cost(const Match<Aggregation>&) { return 1.0; }
497 : : static ConditionSet pre_condition(std::size_t child_idx,
498 : : const std::tuple<const AggregationOperator*> &partial_inner_nodes);
499 : : static ConditionSet post_condition(const Match<Aggregation> &M);
500 : : };
501 : :
502 : : template<bool CmpPredicated>
503 : : struct Quicksort : PhysicalOperator<Quicksort<CmpPredicated>, SortingOperator>
504 : : {
505 : : static void execute(const Match<Quicksort> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
506 : 0 : static double cost(const Match<Quicksort>&) { return M_CONSTEXPR_COND(CmpPredicated, 1.0, 1.1); }
507 : : static ConditionSet pre_condition(std::size_t child_idx,
508 : : const std::tuple<const SortingOperator*> &partial_inner_nodes);
509 : : static ConditionSet post_condition(const Match<Quicksort> &M);
510 : : };
511 : :
512 : : struct NoOpSorting : PhysicalOperator<NoOpSorting, SortingOperator>
513 : : {
514 : : static void execute(const Match<NoOpSorting> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
515 : 0 : static double cost(const Match<NoOpSorting>&) { return 0.0; }
516 : : static ConditionSet pre_condition(std::size_t child_idx,
517 : : const std::tuple<const SortingOperator*> &partial_inner_nodes);
518 : : };
519 : :
520 : : template<bool Predicated>
521 : : struct NestedLoopsJoin : PhysicalOperator<NestedLoopsJoin<Predicated>, JoinOperator>
522 : : {
523 : : static void execute(const Match<NestedLoopsJoin> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
524 : : static double cost(const Match<NestedLoopsJoin> &M);
525 : : static ConditionSet pre_condition(std::size_t child_idx, const std::tuple<const JoinOperator*> &partial_inner_nodes);
526 : : static ConditionSet
527 : : adapt_post_conditions(const Match<NestedLoopsJoin> &M,
528 : : std::vector<std::reference_wrapper<const ConditionSet>> &&post_cond_children);
529 : : };
530 : :
531 : : template<bool UniqueBuild, bool Predicated>
532 : : struct SimpleHashJoin
533 : : : PhysicalOperator<SimpleHashJoin<UniqueBuild, Predicated>, pattern_t<JoinOperator, Wildcard, Wildcard>>
534 : : {
535 : : static void execute(const Match<SimpleHashJoin> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
536 : : static double cost(const Match<SimpleHashJoin> &M);
537 : : static ConditionSet
538 : : pre_condition(std::size_t child_idx,
539 : : const std::tuple<const JoinOperator*, const Wildcard*, const Wildcard*> &partial_inner_nodes);
540 : : static ConditionSet
541 : : adapt_post_conditions(const Match<SimpleHashJoin> &M,
542 : : std::vector<std::reference_wrapper<const ConditionSet>> &&post_cond_children);
543 : : };
544 : :
545 : : template<bool SortLeft, bool SortRight, bool Predicated, bool CmpPredicated>
546 : : struct SortMergeJoin
547 : : : PhysicalOperator<SortMergeJoin<SortLeft, SortRight, Predicated, CmpPredicated>,
548 : : pattern_t<JoinOperator, Wildcard, Wildcard>>
549 : : {
550 : : static void execute(const Match<SortMergeJoin> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
551 : : static double cost(const Match<SortMergeJoin> &M);
552 : : static ConditionSet
553 : : pre_condition(std::size_t child_idx,
554 : : const std::tuple<const JoinOperator*, const Wildcard*, const Wildcard*> &partial_inner_nodes);
555 : : static ConditionSet
556 : : adapt_post_conditions(const Match<SortMergeJoin> &M,
557 : : std::vector<std::reference_wrapper<const ConditionSet>> &&post_cond_children);
558 : : };
559 : :
560 : : struct Limit : PhysicalOperator<Limit, LimitOperator>
561 : : {
562 : : static void execute(const Match<Limit> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
563 : 0 : static double cost(const Match<Limit>&) { return 1.0; }
564 : : static ConditionSet pre_condition(std::size_t child_idx,
565 : : const std::tuple<const LimitOperator*> &partial_inner_nodes);
566 : : };
567 : :
568 : : struct HashBasedGroupJoin
569 : : : PhysicalOperator<HashBasedGroupJoin, pattern_t<GroupingOperator, pattern_t<JoinOperator, Wildcard, Wildcard>>>
570 : : {
571 : : static void execute(const Match<HashBasedGroupJoin> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
572 : : static double cost(const Match<HashBasedGroupJoin>&);
573 : : static ConditionSet
574 : : pre_condition(std::size_t child_idx,
575 : : const std::tuple<const GroupingOperator*, const JoinOperator*, const Wildcard*, const Wildcard*>
576 : : &partial_inner_nodes);
577 : : static ConditionSet post_condition(const Match<HashBasedGroupJoin> &M);
578 : : };
579 : :
580 : : }
581 : :
582 : : /** Registers physical Wasm operators in \p phys_opt depending on the set CLI options. */
583 : : void register_wasm_operators(PhysicalOptimizer &phys_opt);
584 : :
585 : : template<typename T>
586 : 0 : void execute_buffered(const Match<T> &M, const Schema &schema,
587 : : const std::unique_ptr<const storage::DataLayoutFactory> &buffer_factory,
588 : : std::size_t buffer_num_tuples, setup_t setup, pipeline_t pipeline, teardown_t teardown)
589 : : {
590 [ # # # # : 0 : if (buffer_factory) {
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
591 [ # # # # : 0 : auto buffer_schema = schema.drop_constants().deduplicate();
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
592 [ # # # # : 0 : if (buffer_schema.num_entries()) {
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
593 : : /* Use global buffer since own operator may be executed partially in multiple function calls. */
594 [ # # # # : 0 : wasm::GlobalBuffer buffer(buffer_schema, *buffer_factory, wasm::CodeGenContext::Get().num_simd_lanes() > 1,
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
595 : 0 : buffer_num_tuples, std::move(setup), std::move(pipeline), std::move(teardown));
596 [ # # # # : 0 : T::execute(
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
597 : 0 : /* M= */ M,
598 [ # # # # : 0 : /* setup= */ setup_t::Make_Without_Parent([&buffer](){ buffer.setup(); }),
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
599 : 0 : /* pipeline= */ [&buffer](){ buffer.consume(); },
600 [ # # # # : 0 : /* teardown= */ teardown_t::Make_Without_Parent([&buffer](){ buffer.teardown(); })
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
601 : : );
602 [ # # # # : 0 : buffer.resume_pipeline();
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
603 : 0 : } else {
604 [ # # # # : 0 : T::execute(M, std::move(setup), std::move(pipeline), std::move(teardown));
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
605 : : }
606 : 0 : } else {
607 [ # # # # : 0 : T::execute(M, std::move(setup), std::move(pipeline), std::move(teardown));
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
608 : : }
609 : 0 : }
610 : :
611 : : namespace wasm {
612 : :
613 : : /** An abstract `MatchBase` for the `WasmV8` backend. Adds accept methods for respective visitor. */
614 : : struct MatchBase : m::MatchBase
615 : : {
616 : : virtual void accept(MatchBaseVisitor &v) = 0;
617 : : virtual void accept(ConstMatchBaseVisitor &v) const = 0;
618 : : };
619 : :
620 : : /** Intermediate match type for leaves, i.e. physical operator matches without children. */
621 : : struct MatchLeaf : wasm::MatchBase { };
622 : : /** Intermediate match type for physical operator matches with a single child. */
623 : : struct MatchSingleChild : wasm::MatchBase
624 : : {
625 : : unsharable_shared_ptr<const wasm::MatchBase> child;
626 : :
627 : 0 : MatchSingleChild(std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
628 [ # # ]: 0 : : child(as<const wasm::MatchBase>(std::move(children[0])))
629 : 0 : {
630 [ # # ]: 0 : M_insist(children.size() == 1);
631 : 0 : }
632 : : };
633 : : /** Intermediate match type for physical operator matches with multiple children. */
634 : : struct MatchMultipleChildren : wasm::MatchBase
635 : : {
636 : : std::vector<unsharable_shared_ptr<const wasm::MatchBase>> children;
637 : :
638 : 0 : MatchMultipleChildren(std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
639 [ # # ]: 0 : : children([&children](){
640 : 0 : std::vector<unsharable_shared_ptr<const wasm::MatchBase>> res;
641 [ # # ]: 0 : for (auto &c : children)
642 [ # # # # ]: 0 : res.push_back(as<const wasm::MatchBase>(std::move(c)));
643 : 0 : return res;
644 [ # # ]: 0 : }())
645 : 0 : {
646 [ # # ]: 0 : M_insist(children.size() >= 2);
647 : 0 : }
648 : : };
649 : :
650 : : };
651 : :
652 : : template<>
653 : : struct Match<wasm::NoOp> : wasm::MatchSingleChild
654 : : {
655 : : const NoOpOperator &noop;
656 : :
657 : 0 : Match(const NoOpOperator *noop, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
658 : 0 : : wasm::MatchSingleChild(std::move(children))
659 : 0 : , noop(*noop)
660 : 0 : { }
661 : :
662 : 0 : void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
663 [ # # ]: 0 : wasm::NoOp::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
664 : 0 : }
665 : :
666 : 0 : const Operator & get_matched_root() const override { return noop; }
667 : :
668 : : void accept(wasm::MatchBaseVisitor &v) override;
669 : : void accept(wasm::ConstMatchBaseVisitor &v) const override;
670 : :
671 : : protected:
672 : : void print(std::ostream &out, unsigned level) const override;
673 : : };
674 : :
675 : : template<bool SIMDfied>
676 : : struct Match<wasm::Callback<SIMDfied>> : wasm::MatchSingleChild
677 : : {
678 : : const CallbackOperator &callback;
679 : 0 : std::unique_ptr<const storage::DataLayoutFactory> result_set_factory =
680 [ # # # # : 0 : M_notnull(options::hard_pipeline_breaker_layout.get())->clone();
# # # # ]
681 : 0 : std::size_t result_set_window_size = options::result_set_window_size;
682 : :
683 : 0 : Match(const CallbackOperator *callback, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
684 : 0 : : wasm::MatchSingleChild(std::move(children))
685 : 0 : , callback(*callback)
686 : 0 : { }
687 : :
688 : 0 : void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
689 [ # # # # ]: 0 : wasm::Callback<SIMDfied>::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
690 : 0 : }
691 : :
692 : 0 : const Operator & get_matched_root() const override { return callback; }
693 : :
694 : : void accept(wasm::MatchBaseVisitor &v) override;
695 : : void accept(wasm::ConstMatchBaseVisitor &v) const override;
696 : :
697 : : protected:
698 : : void print(std::ostream &out, unsigned level) const override;
699 : : };
700 : :
701 : : template<bool SIMDfied>
702 : : struct Match<wasm::Print<SIMDfied>> : wasm::MatchSingleChild
703 : : {
704 : : const PrintOperator &print_op;
705 : 0 : std::unique_ptr<const storage::DataLayoutFactory> result_set_factory =
706 [ # # # # : 0 : M_notnull(options::hard_pipeline_breaker_layout.get())->clone();
# # # # ]
707 : 0 : std::size_t result_set_window_size = options::result_set_window_size;
708 : :
709 : 0 : Match(const PrintOperator *print, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
710 : 0 : : wasm::MatchSingleChild(std::move(children))
711 : 0 : , print_op(*print)
712 : 0 : { }
713 : :
714 : 0 : void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
715 [ # # # # ]: 0 : wasm::Print<SIMDfied>::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
716 : 0 : }
717 : :
718 : 0 : const Operator & get_matched_root() const override { return print_op; }
719 : :
720 : : void accept(wasm::MatchBaseVisitor &v) override;
721 : : void accept(wasm::ConstMatchBaseVisitor &v) const override;
722 : :
723 : : protected:
724 : : void print(std::ostream &out, unsigned level) const override;
725 : : };
726 : :
727 : : template<bool SIMDfied>
728 : : struct Match<wasm::Scan<SIMDfied>> : wasm::MatchLeaf
729 : : {
730 : : const ScanOperator &scan;
731 : : private:
732 : 10 : std::unique_ptr<const storage::DataLayoutFactory> buffer_factory_ =
733 [ + - - + : 10 : bool(options::soft_pipeline_breaker bitand option_configs::SoftPipelineBreakerStrategy::AFTER_SCAN)
# # # # ]
734 [ # # # # : 0 : ? M_notnull(options::soft_pipeline_breaker_layout.get())->clone()
# # # # ]
735 : 10 : : std::unique_ptr<storage::DataLayoutFactory>();
736 : 10 : std::size_t buffer_num_tuples_ = options::soft_pipeline_breaker_num_tuples;
737 : :
738 : : public:
739 : 10 : Match(const ScanOperator *scan, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
740 : 10 : : scan(*scan)
741 : 10 : {
742 [ - + # # ]: 10 : M_insist(children.empty());
743 : 10 : }
744 : :
745 : 0 : void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
746 [ # # # # ]: 0 : if (buffer_factory_) {
747 [ # # # # ]: 0 : auto buffer_schema = scan.schema().drop_constants().deduplicate();
748 [ # # # # : 0 : if (buffer_schema.num_entries()) {
# # # # ]
749 : : /* Use local buffer since scan loop will not be executed partially in multiple function calls. */
750 [ # # # # : 0 : wasm::LocalBuffer buffer(buffer_schema, *buffer_factory_, SIMDfied or options::simd, buffer_num_tuples_,
# # # # ]
751 : 0 : std::move(setup), std::move(pipeline), std::move(teardown));
752 [ # # # # ]: 0 : wasm::Scan<SIMDfied>::execute(
753 : : /* M= */ *this,
754 [ # # # # ]: 0 : /* setup= */ setup_t::Make_Without_Parent([&buffer](){ buffer.setup(); }),
755 : 0 : /* pipeline= */ [&buffer](){ buffer.consume(); },
756 [ # # # # ]: 0 : /* teardown= */ teardown_t::Make_Without_Parent([&buffer](){
757 : 0 : buffer.resume_pipeline(); // must be placed before teardown method for local buffers
758 : 0 : buffer.teardown();
759 : 0 : })
760 : : );
761 : 0 : } else {
762 [ # # # # ]: 0 : wasm::Scan<SIMDfied>::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
763 : : }
764 : 0 : } else {
765 [ # # # # ]: 0 : wasm::Scan<SIMDfied>::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
766 : : }
767 : 0 : }
768 : :
769 : 0 : const Operator & get_matched_root() const override { return scan; }
770 : :
771 : : void accept(wasm::MatchBaseVisitor &v) override;
772 : : void accept(wasm::ConstMatchBaseVisitor &v) const override;
773 : :
774 : : protected:
775 : : void print(std::ostream &out, unsigned level) const override;
776 : : };
777 : :
778 : : template<idx::IndexMethod IndexMethod>
779 : : struct Match<wasm::IndexScan<IndexMethod>> : wasm::MatchLeaf
780 : : {
781 : : const ScanOperator &scan;
782 : : const FilterOperator &filter;
783 : 0 : std::size_t batch_size = options::index_sequential_scan_batch_size;
784 : : private:
785 : 0 : std::unique_ptr<const storage::DataLayoutFactory> buffer_factory_ =
786 [ # # # # : 0 : bool(options::soft_pipeline_breaker bitand option_configs::SoftPipelineBreakerStrategy::AFTER_INDEX_SCAN)
# # # # ]
787 [ # # # # : 0 : ? M_notnull(options::soft_pipeline_breaker_layout.get())->clone()
# # # # ]
788 : 0 : : std::unique_ptr<storage::DataLayoutFactory>();
789 : 0 : std::size_t buffer_num_tuples_ = options::soft_pipeline_breaker_num_tuples;
790 : :
791 : : public:
792 : 0 : Match(const FilterOperator *filter, const ScanOperator *scan,
793 : : std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
794 : 0 : : scan(*scan)
795 : 0 : , filter(*filter)
796 : 0 : {
797 [ # # # # ]: 0 : M_insist(children.empty());
798 : 0 : }
799 : :
800 : 0 : void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
801 [ # # # # : 0 : execute_buffered(*this, filter.schema(), buffer_factory_, buffer_num_tuples_,
# # # # ]
802 : 0 : std::move(setup), std::move(pipeline), std::move(teardown));
803 : 0 : }
804 : :
805 : 0 : const Operator & get_matched_root() const override { return filter; }
806 : :
807 : : void accept(wasm::MatchBaseVisitor &v) override;
808 : : void accept(wasm::ConstMatchBaseVisitor &v) const override;
809 : :
810 : : protected:
811 : : void print(std::ostream &out, unsigned level) const override;
812 : : };
813 : :
814 : : template<bool Predicated>
815 : : struct Match<wasm::Filter<Predicated>> : wasm::MatchSingleChild
816 : : {
817 : : const FilterOperator &filter;
818 : : private:
819 : 0 : std::unique_ptr<const storage::DataLayoutFactory> buffer_factory_ =
820 [ # # # # : 0 : bool(options::soft_pipeline_breaker bitand option_configs::SoftPipelineBreakerStrategy::AFTER_FILTER)
# # # # ]
821 [ # # # # : 0 : ? M_notnull(options::soft_pipeline_breaker_layout.get())->clone()
# # # # ]
822 : 0 : : std::unique_ptr<storage::DataLayoutFactory>();
823 : 0 : std::size_t buffer_num_tuples_ = options::soft_pipeline_breaker_num_tuples;
824 : :
825 : : public:
826 : 0 : Match(const FilterOperator *filter, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
827 : 0 : : wasm::MatchSingleChild(std::move(children))
828 : 0 : , filter(*filter)
829 : 0 : { }
830 : :
831 : 0 : void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
832 [ # # # # : 0 : execute_buffered(*this, filter.schema(), buffer_factory_, buffer_num_tuples_,
# # # # ]
833 : 0 : std::move(setup), std::move(pipeline), std::move(teardown));
834 : 0 : }
835 : :
836 : 0 : const Operator & get_matched_root() const override { return filter; }
837 : :
838 : : void accept(wasm::MatchBaseVisitor &v) override;
839 : : void accept(wasm::ConstMatchBaseVisitor &v) const override;
840 : :
841 : : protected:
842 : : void print(std::ostream &out, unsigned level) const override;
843 : : };
844 : :
845 : : template<>
846 : : struct Match<wasm::LazyDisjunctiveFilter> : wasm::MatchSingleChild
847 : : {
848 : : const DisjunctiveFilterOperator &filter;
849 : : private:
850 : 0 : std::unique_ptr<const storage::DataLayoutFactory> buffer_factory_ =
851 [ # # ]: 0 : bool(options::soft_pipeline_breaker bitand option_configs::SoftPipelineBreakerStrategy::AFTER_FILTER)
852 [ # # # # ]: 0 : ? M_notnull(options::soft_pipeline_breaker_layout.get())->clone()
853 : 0 : : std::unique_ptr<storage::DataLayoutFactory>();
854 : 0 : std::size_t buffer_num_tuples_ = options::soft_pipeline_breaker_num_tuples;
855 : :
856 : : public:
857 : 0 : Match(const DisjunctiveFilterOperator *filter, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
858 : 0 : : wasm::MatchSingleChild(std::move(children))
859 : 0 : , filter(*filter)
860 : 0 : { }
861 : :
862 : 0 : void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
863 [ # # # # ]: 0 : execute_buffered(*this, filter.schema(), buffer_factory_, buffer_num_tuples_,
864 : 0 : std::move(setup), std::move(pipeline), std::move(teardown));
865 : 0 : }
866 : :
867 : 0 : const Operator & get_matched_root() const override { return filter; }
868 : :
869 : : void accept(wasm::MatchBaseVisitor &v) override;
870 : : void accept(wasm::ConstMatchBaseVisitor &v) const override;
871 : :
872 : : protected:
873 : : void print(std::ostream &out, unsigned level) const override;
874 : : };
875 : :
876 : : template<>
877 : : struct Match<wasm::Projection> : wasm::MatchBase
878 : : {
879 : : const ProjectionOperator &projection;
880 : : std::optional<unsharable_shared_ptr<const wasm::MatchBase>> child;
881 : : private:
882 : 0 : std::unique_ptr<const storage::DataLayoutFactory> buffer_factory_ =
883 [ # # ]: 0 : bool(options::soft_pipeline_breaker bitand option_configs::SoftPipelineBreakerStrategy::AFTER_PROJECTION)
884 [ # # # # ]: 0 : ? M_notnull(options::soft_pipeline_breaker_layout.get())->clone()
885 : 0 : : std::unique_ptr<storage::DataLayoutFactory>();
886 : 0 : std::size_t buffer_num_tuples_ = options::soft_pipeline_breaker_num_tuples;
887 : :
888 : : public:
889 : 0 : Match(const ProjectionOperator *projection, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
890 : 0 : : projection(*projection)
891 : 0 : {
892 [ # # ]: 0 : if (not children.empty()) {
893 [ # # ]: 0 : M_insist(children.size() == 1);
894 [ # # ]: 0 : child = as<const wasm::MatchBase>(std::move(children[0]));
895 : 0 : }
896 : 0 : }
897 : :
898 : 0 : void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
899 [ # # # # ]: 0 : execute_buffered(*this, projection.schema(), buffer_factory_, buffer_num_tuples_,
900 : 0 : std::move(setup), std::move(pipeline), std::move(teardown));
901 : 0 : }
902 : :
903 : 0 : const Operator & get_matched_root() const override { return projection; }
904 : :
905 : : void accept(wasm::MatchBaseVisitor &v) override;
906 : : void accept(wasm::ConstMatchBaseVisitor &v) const override;
907 : :
908 : : protected:
909 : : void print(std::ostream &out, unsigned level) const override;
910 : : };
911 : :
912 : : template<>
913 : : struct Match<wasm::HashBasedGrouping> : wasm::MatchSingleChild
914 : : {
915 : : const GroupingOperator &grouping;
916 : 0 : bool use_open_addressing_hashing =
917 : 0 : bool(options::hash_table_implementation bitand option_configs::HashTableImplementation::OPEN_ADDRESSING);
918 : 0 : bool use_in_place_values = bool(options::hash_table_storing_strategy bitand option_configs::StoringStrategy::IN_PLACE);
919 : 0 : bool use_quadratic_probing = bool(options::hash_table_probing_strategy bitand option_configs::ProbingStrategy::QUADRATIC);
920 : 0 : double load_factor =
921 [ # # ]: 0 : use_open_addressing_hashing ? options::load_factor_open_addressing : options::load_factor_chained;
922 : :
923 : 0 : Match(const GroupingOperator *grouping, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
924 : 0 : : wasm::MatchSingleChild(std::move(children))
925 : 0 : , grouping(*grouping)
926 : 0 : { }
927 : :
928 : 0 : void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
929 [ # # ]: 0 : wasm::HashBasedGrouping::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
930 : 0 : }
931 : :
932 : 0 : const Operator & get_matched_root() const override { return grouping; }
933 : :
934 : : void accept(wasm::MatchBaseVisitor &v) override;
935 : : void accept(wasm::ConstMatchBaseVisitor &v) const override;
936 : :
937 : : protected:
938 : : void print(std::ostream &out, unsigned level) const override;
939 : : };
940 : :
941 : : template<>
942 : : struct Match<wasm::OrderedGrouping> : wasm::MatchSingleChild
943 : : {
944 : : const GroupingOperator &grouping;
945 : :
946 : 0 : Match(const GroupingOperator *grouping, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
947 : 0 : : wasm::MatchSingleChild(std::move(children))
948 : 0 : , grouping(*grouping)
949 : 0 : { }
950 : :
951 : 0 : void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
952 [ # # ]: 0 : wasm::OrderedGrouping::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
953 : 0 : }
954 : :
955 : 0 : const Operator & get_matched_root() const override { return grouping; }
956 : :
957 : : void accept(wasm::MatchBaseVisitor &v) override;
958 : : void accept(wasm::ConstMatchBaseVisitor &v) const override;
959 : :
960 : : protected:
961 : : void print(std::ostream &out, unsigned level) const override;
962 : : };
963 : :
964 : : template<>
965 : : struct Match<wasm::Aggregation> : wasm::MatchSingleChild
966 : : {
967 : : const AggregationOperator &aggregation;
968 : :
969 : 0 : Match(const AggregationOperator *aggregation, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
970 : 0 : : wasm::MatchSingleChild(std::move(children))
971 : 0 : , aggregation(*aggregation)
972 : 0 : { }
973 : :
974 : 0 : void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
975 [ # # ]: 0 : wasm::Aggregation::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
976 : 0 : }
977 : :
978 : 0 : const Operator & get_matched_root() const override { return aggregation; }
979 : :
980 : : void accept(wasm::MatchBaseVisitor &v) override;
981 : : void accept(wasm::ConstMatchBaseVisitor &v) const override;
982 : :
983 : : protected:
984 : : void print(std::ostream &out, unsigned level) const override;
985 : : };
986 : :
987 : : template<bool CmpPredicated>
988 : : struct Match<wasm::Quicksort<CmpPredicated>> : wasm::MatchSingleChild
989 : : {
990 : : const SortingOperator &sorting;
991 : 0 : std::unique_ptr<const storage::DataLayoutFactory> materializing_factory =
992 [ # # # # : 0 : M_notnull(options::hard_pipeline_breaker_layout.get())->clone();
# # # # ]
993 : :
994 : 0 : Match(const SortingOperator *sorting, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
995 : 0 : : wasm::MatchSingleChild(std::move(children))
996 : 0 : , sorting(*sorting)
997 : 0 : { }
998 : :
999 : 0 : void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
1000 [ # # # # ]: 0 : wasm::Quicksort<CmpPredicated>::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
1001 : 0 : }
1002 : :
1003 : 0 : const Operator & get_matched_root() const override { return sorting; }
1004 : :
1005 : : void accept(wasm::MatchBaseVisitor &v) override;
1006 : : void accept(wasm::ConstMatchBaseVisitor &v) const override;
1007 : :
1008 : : protected:
1009 : : void print(std::ostream &out, unsigned level) const override;
1010 : : };
1011 : :
1012 : : template<>
1013 : : struct Match<wasm::NoOpSorting> : wasm::MatchSingleChild
1014 : : {
1015 : : const SortingOperator &sorting;
1016 : :
1017 : 0 : Match(const SortingOperator *sorting, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
1018 : 0 : : wasm::MatchSingleChild(std::move(children))
1019 : 0 : , sorting(*sorting)
1020 : 0 : { }
1021 : :
1022 : 0 : void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
1023 [ # # ]: 0 : wasm::NoOpSorting::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
1024 : 0 : }
1025 : :
1026 : 0 : const Operator & get_matched_root() const override { return sorting; }
1027 : :
1028 : : void accept(wasm::MatchBaseVisitor &v) override;
1029 : : void accept(wasm::ConstMatchBaseVisitor &v) const override;
1030 : :
1031 : : protected:
1032 : : void print(std::ostream &out, unsigned level) const override;
1033 : : };
1034 : :
1035 : : template<bool Predicated>
1036 : : struct Match<wasm::NestedLoopsJoin<Predicated>> : wasm::MatchMultipleChildren
1037 : : {
1038 : : const JoinOperator &join;
1039 : : std::vector<std::unique_ptr<const storage::DataLayoutFactory>> materializing_factories_;
1040 : : private:
1041 : 0 : std::unique_ptr<const storage::DataLayoutFactory> buffer_factory_ =
1042 [ # # # # : 0 : bool(options::soft_pipeline_breaker bitand option_configs::SoftPipelineBreakerStrategy::AFTER_NESTED_LOOPS_JOIN)
# # # # ]
1043 [ # # # # : 0 : ? M_notnull(options::soft_pipeline_breaker_layout.get())->clone()
# # # # ]
1044 : 0 : : std::unique_ptr<storage::DataLayoutFactory>();
1045 : 0 : std::size_t buffer_num_tuples_ = options::soft_pipeline_breaker_num_tuples;
1046 : :
1047 : : public:
1048 : 0 : Match(const JoinOperator *join, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
1049 : 0 : : wasm::MatchMultipleChildren(std::move(children))
1050 : 0 : , join(*join)
1051 : 0 : {
1052 [ # # # # ]: 0 : for (std::size_t i = 0; i < children.size() - 1; ++i)
1053 [ # # # # : 0 : materializing_factories_.push_back(M_notnull(options::hard_pipeline_breaker_layout.get())->clone());
# # # # #
# # # ]
1054 : 0 : }
1055 : :
1056 : 0 : void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
1057 [ # # # # : 0 : execute_buffered(*this, join.schema(), buffer_factory_, buffer_num_tuples_,
# # # # ]
1058 : 0 : std::move(setup), std::move(pipeline), std::move(teardown));
1059 : 0 : }
1060 : :
1061 : 0 : const Operator & get_matched_root() const override { return join; }
1062 : :
1063 : : void accept(wasm::MatchBaseVisitor &v) override;
1064 : : void accept(wasm::ConstMatchBaseVisitor &v) const override;
1065 : :
1066 : : protected:
1067 : : void print(std::ostream &out, unsigned level) const override;
1068 : : };
1069 : :
1070 : : template<bool UniqueBuild, bool Predicated>
1071 : : struct Match<wasm::SimpleHashJoin<UniqueBuild, Predicated>> : wasm::MatchMultipleChildren
1072 : : {
1073 : : const JoinOperator &join;
1074 : : const Wildcard &build;
1075 : : const Wildcard &probe;
1076 : 0 : bool use_open_addressing_hashing =
1077 [ # # # # : 0 : bool(options::hash_table_implementation bitand option_configs::HashTableImplementation::OPEN_ADDRESSING);
# # # # ]
1078 [ # # # # : 0 : bool use_in_place_values = bool(options::hash_table_storing_strategy bitand option_configs::StoringStrategy::IN_PLACE);
# # # # ]
1079 [ # # # # : 0 : bool use_quadratic_probing = bool(options::hash_table_probing_strategy bitand option_configs::ProbingStrategy::QUADRATIC);
# # # # ]
1080 : 0 : double load_factor =
1081 [ # # # # : 0 : use_open_addressing_hashing ? options::load_factor_open_addressing : options::load_factor_chained;
# # # # ]
1082 : : private:
1083 : 0 : std::unique_ptr<const storage::DataLayoutFactory> buffer_factory_ =
1084 [ # # # # : 0 : bool(options::soft_pipeline_breaker bitand option_configs::SoftPipelineBreakerStrategy::AFTER_SIMPLE_HASH_JOIN)
# # # # #
# # # # #
# # ]
1085 [ # # # # : 0 : ? M_notnull(options::soft_pipeline_breaker_layout.get())->clone()
# # # # #
# # # # #
# # ]
1086 : 0 : : std::unique_ptr<storage::DataLayoutFactory>();
1087 : 0 : std::size_t buffer_num_tuples_ = options::soft_pipeline_breaker_num_tuples;
1088 : :
1089 : : public:
1090 : 0 : Match(const JoinOperator *join, const Wildcard *build, const Wildcard *probe,
1091 : : std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
1092 : 0 : : wasm::MatchMultipleChildren(std::move(children))
1093 : 0 : , join(*join)
1094 : 0 : , build(*build)
1095 : 0 : , probe(*probe)
1096 : 0 : {
1097 [ # # # # : 0 : M_insist(children.size() == 2);
# # # # ]
1098 : 0 : }
1099 : :
1100 : 0 : void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
1101 [ # # # # : 0 : execute_buffered(*this, join.schema(), buffer_factory_, buffer_num_tuples_,
# # # # #
# # # # #
# # ]
1102 : 0 : std::move(setup), std::move(pipeline), std::move(teardown));
1103 : 0 : }
1104 : :
1105 : 0 : const Operator & get_matched_root() const override { return join; }
1106 : :
1107 : : void accept(wasm::MatchBaseVisitor &v) override;
1108 : : void accept(wasm::ConstMatchBaseVisitor &v) const override;
1109 : :
1110 : : protected:
1111 : : void print(std::ostream &out, unsigned level) const override;
1112 : : };
1113 : :
1114 : : template<bool SortLeft, bool SortRight, bool Predicated, bool CmpPredicated>
1115 : : struct Match<wasm::SortMergeJoin<SortLeft, SortRight, Predicated, CmpPredicated>> : wasm::MatchMultipleChildren
1116 : : {
1117 : : const JoinOperator &join;
1118 : : const Wildcard &parent; ///< the referenced relation with unique join attributes
1119 : : const Wildcard &child; ///< the relation referencing the parent relation
1120 : 0 : std::unique_ptr<const storage::DataLayoutFactory> left_materializing_factory =
1121 [ # # # # : 0 : M_notnull(options::hard_pipeline_breaker_layout.get())->clone();
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
1122 : 0 : std::unique_ptr<const storage::DataLayoutFactory> right_materializing_factory =
1123 [ # # # # : 0 : M_notnull(options::hard_pipeline_breaker_layout.get())->clone();
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
1124 : :
1125 : 0 : Match(const JoinOperator *join, const Wildcard *parent, const Wildcard *child,
1126 : : std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
1127 : 0 : : wasm::MatchMultipleChildren(std::move(children))
1128 : 0 : , join(*join)
1129 : 0 : , parent(*parent)
1130 : 0 : , child(*child)
1131 : 0 : {
1132 [ # # # # : 0 : M_insist(children.size() == 2);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
1133 : 0 : }
1134 : :
1135 : 0 : void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
1136 [ # # # # : 0 : wasm::SortMergeJoin<SortLeft, SortRight, Predicated, CmpPredicated>::execute(
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
1137 : 0 : *this, std::move(setup), std::move(pipeline), std::move(teardown)
1138 : : );
1139 : 0 : }
1140 : :
1141 : 0 : const Operator & get_matched_root() const override { return join; }
1142 : :
1143 : : void accept(wasm::MatchBaseVisitor &v) override;
1144 : : void accept(wasm::ConstMatchBaseVisitor &v) const override;
1145 : :
1146 : : protected:
1147 : : void print(std::ostream &out, unsigned level) const override;
1148 : : };
1149 : :
1150 : : template<>
1151 : : struct Match<wasm::Limit> : wasm::MatchSingleChild
1152 : : {
1153 : : const LimitOperator &limit;
1154 : :
1155 : 0 : Match(const LimitOperator *limit, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
1156 : 0 : : wasm::MatchSingleChild(std::move(children))
1157 : 0 : , limit(*limit)
1158 : 0 : { }
1159 : :
1160 : 0 : void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
1161 [ # # ]: 0 : wasm::Limit::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
1162 : 0 : }
1163 : :
1164 : 0 : const Operator & get_matched_root() const override { return limit; }
1165 : :
1166 : : void accept(wasm::MatchBaseVisitor &v) override;
1167 : : void accept(wasm::ConstMatchBaseVisitor &v) const override;
1168 : :
1169 : : protected:
1170 : : void print(std::ostream &out, unsigned level) const override;
1171 : : };
1172 : :
1173 : : template<>
1174 : : struct Match<wasm::HashBasedGroupJoin> : wasm::MatchMultipleChildren
1175 : : {
1176 : : const GroupingOperator &grouping;
1177 : : const JoinOperator &join;
1178 : : const Wildcard &build;
1179 : : const Wildcard &probe;
1180 : 0 : bool use_open_addressing_hashing =
1181 : 0 : bool(options::hash_table_implementation bitand option_configs::HashTableImplementation::OPEN_ADDRESSING);
1182 : 0 : bool use_in_place_values = bool(options::hash_table_storing_strategy bitand option_configs::StoringStrategy::IN_PLACE);
1183 : 0 : bool use_quadratic_probing = bool(options::hash_table_probing_strategy bitand option_configs::ProbingStrategy::QUADRATIC);
1184 : 0 : double load_factor =
1185 [ # # ]: 0 : use_open_addressing_hashing ? options::load_factor_open_addressing : options::load_factor_chained;
1186 : : private:
1187 : 0 : std::unique_ptr<const storage::DataLayoutFactory> buffer_factory_ =
1188 [ # # ]: 0 : bool(options::soft_pipeline_breaker bitand option_configs::SoftPipelineBreakerStrategy::AFTER_HASH_BASED_GROUP_JOIN)
1189 [ # # # # ]: 0 : ? M_notnull(options::soft_pipeline_breaker_layout.get())->clone()
1190 : 0 : : std::unique_ptr<storage::DataLayoutFactory>();
1191 : 0 : std::size_t buffer_num_tuples_ = options::soft_pipeline_breaker_num_tuples;
1192 : :
1193 : : public:
1194 : 0 : Match(const GroupingOperator* grouping, const JoinOperator *join, const Wildcard *build, const Wildcard *probe,
1195 : : std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
1196 : 0 : : wasm::MatchMultipleChildren(std::move(children))
1197 : 0 : , grouping(*grouping)
1198 : 0 : , join(*join)
1199 : 0 : , build(*build)
1200 : 0 : , probe(*probe)
1201 : 0 : {
1202 [ # # ]: 0 : M_insist(children.size() == 2);
1203 : 0 : }
1204 : :
1205 : 0 : void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
1206 [ # # # # ]: 0 : execute_buffered(*this, grouping.schema(), buffer_factory_, buffer_num_tuples_,
1207 : 0 : std::move(setup), std::move(pipeline), std::move(teardown));
1208 : 0 : }
1209 : :
1210 : 0 : const Operator & get_matched_root() const override { return grouping; }
1211 : :
1212 : : void accept(wasm::MatchBaseVisitor &v) override;
1213 : : void accept(wasm::ConstMatchBaseVisitor &v) const override;
1214 : :
1215 : : protected:
1216 : : void print(std::ostream &out, unsigned level) const override;
1217 : : };
1218 : :
1219 : : namespace wasm {
1220 : :
1221 : : #define M_WASM_VISITABLE_MATCH_LIST(X) \
1222 : : M_WASM_MATCH_LIST(X) \
1223 : : X(MatchLeaf) \
1224 : : X(MatchSingleChild) \
1225 : : X(MatchMultipleChildren)
1226 : :
1227 : : M_DECLARE_VISITOR(MatchBaseVisitor, wasm::MatchBase, M_WASM_VISITABLE_MATCH_LIST)
1228 : : M_DECLARE_VISITOR(ConstMatchBaseVisitor, const wasm::MatchBase, M_WASM_VISITABLE_MATCH_LIST)
1229 : :
1230 : : /** A generic base class for implementing recursive `wasm::MatchBase` visitors. */
1231 : : template<bool C>
1232 : : struct TheRecursiveMatchBaseVisitorBase : std::conditional_t<C, ConstMatchBaseVisitor, MatchBaseVisitor>
1233 : : {
1234 : : using super = std::conditional_t<C, ConstMatchBaseVisitor, MatchBaseVisitor>;
1235 : : template<typename T> using Const = typename super::template Const<T>;
1236 : :
1237 : 0 : virtual ~TheRecursiveMatchBaseVisitorBase() { }
1238 : :
1239 : : /* omit using super::operator() to convert to intermediate match classes and call recursive implementation */
1240 : 0 : void operator()(Const<MatchBase> &M) override { super::operator()(M); }
1241 : 0 : void operator()(Const<MatchLeaf>&) override { /* nothing to be done */ }
1242 : 0 : void operator()(Const<MatchSingleChild> &M) override { (*this)(*M.child); }
1243 [ # # ]: 0 : void operator()(Const<Match<Projection>> &M) override { if (M.child) (*this)(**M.child); }
1244 [ # # ]: 0 : void operator()(Const<MatchMultipleChildren> &M) override { for (auto &c : M.children) (*this)(*c); }
1245 : : };
1246 : :
1247 : : using RecursiveConstMatchBaseVisitorBase = TheRecursiveMatchBaseVisitorBase<true>;
1248 : :
1249 : : template<bool C>
1250 : : struct ThePreOrderMatchBaseVisitor : std::conditional_t<C, ConstMatchBaseVisitor, MatchBaseVisitor>
1251 : : {
1252 : : using super = std::conditional_t<C, ConstMatchBaseVisitor, MatchBaseVisitor>;
1253 : : template<typename T> using Const = typename super::template Const<T>;
1254 : :
1255 : 0 : virtual ~ThePreOrderMatchBaseVisitor() { }
1256 : :
1257 : : void operator()(Const<MatchBase>&);
1258 : : };
1259 : :
1260 : : template<bool C>
1261 : : struct ThePostOrderMatchBaseVisitor : std::conditional_t<C, ConstMatchBaseVisitor, MatchBaseVisitor>
1262 : : {
1263 : : using super = std::conditional_t<C, ConstMatchBaseVisitor, MatchBaseVisitor>;
1264 : : template<typename T> using Const = typename super::template Const<T>;
1265 : :
1266 : 0 : virtual ~ThePostOrderMatchBaseVisitor() { }
1267 : :
1268 : : void operator()(Const<MatchBase>&);
1269 : : };
1270 : :
1271 : : using ConstPreOrderMatchBaseVisitor = ThePreOrderMatchBaseVisitor<true>;
1272 : : using ConstPostOrderMatchBaseVisitor = ThePostOrderMatchBaseVisitor<true>;
1273 : :
1274 : : M_MAKE_STL_VISITABLE(ConstPreOrderMatchBaseVisitor, const wasm::MatchBase, M_WASM_VISITABLE_MATCH_LIST)
1275 : : M_MAKE_STL_VISITABLE(ConstPostOrderMatchBaseVisitor, const wasm::MatchBase, M_WASM_VISITABLE_MATCH_LIST)
1276 : :
1277 : : #undef M_WASM_VISITABLE_MATCH_LIST
1278 : :
1279 : : }
1280 : :
1281 : : // delayed definitions (must occur *before* explicit instantiation below)
1282 : : #define ACCEPT(CLASS) \
1283 : : inline void CLASS::accept(wasm::MatchBaseVisitor &v) { v(*this); } \
1284 : : inline void CLASS::accept(wasm::ConstMatchBaseVisitor &v) const { v(*this); }
1285 : 0 : M_WASM_MATCH_LIST_NON_TEMPLATED(ACCEPT)
1286 : : #undef ACCEPT
1287 : :
1288 : : #define ACCEPT(CLASS) \
1289 : : template<> inline void CLASS::accept(wasm::MatchBaseVisitor &v) { v(*this); } \
1290 : : template<> inline void CLASS::accept(wasm::ConstMatchBaseVisitor &v) const { v(*this); }
1291 : 0 : M_WASM_MATCH_LIST_TEMPLATED(ACCEPT)
1292 : : #undef ACCEPT
1293 : :
1294 : : }
1295 : :
1296 : :
1297 : : // explicit instantiation declarations
1298 : : #define DECLARE(CLASS) \
1299 : : extern template struct m::wasm::CLASS; \
1300 : : extern template struct m::Match<m::wasm::CLASS>;
1301 : : M_WASM_OPERATOR_LIST_TEMPLATED(DECLARE)
1302 : : #undef DECLARE
|