2 * Copyright 2020 Cerebras Systems. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials provided
14 * with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY CEREBRAS SYSTEMS ''AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CEREBRAS SYSTEMS OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * The views and conclusions contained in the software and documentation
29 * are those of the authors and should not be interpreted as
30 * representing official policies, either expressed or implied, of
41 #include <unordered_map>
42 #include <unordered_set>
44 #include "template_cpp.h"
45 #include "isl_config.h"
47 /* The textual representation of this tuple kind.
49 * By default, the textual representation is just the name.
51 std::string
TupleKind::to_string() const
56 /* Return the parameters of this tuple kind.
58 * By default, there are no parameters.
60 std::vector
<std::string
> TupleKind::params() const
65 /* Apply the substitution "subs" to this tuple kind and return the result.
66 * "self" is a shared pointer to this.
68 * If the name of this tuple kind appears in the substitution,
69 * then return the corresponding tuple kind pointer.
70 * Otherwise, return "self".
72 TupleKindPtr
TupleKind::apply(const Substitution
&subs
,
73 const TupleKindPtr
&self
) const
75 if (subs
.count(name
) != 0)
80 /* Apply the substitution "subs" to "tuple" and return the result.
82 static TupleKindPtr
apply(const TupleKindPtr tuple
, const Substitution
&subs
)
84 return tuple
->apply(subs
, tuple
);
87 /* Return the left child of this tuple kind.
89 * Since this is not a pair, there is no left child.
91 TupleKindPtr
TupleKind::left() const
93 return TupleKindPtr();
96 /* Return the right child of this tuple kind.
98 * Since this is not a pair, there is no right child.
100 TupleKindPtr
TupleKind::right() const
102 return TupleKindPtr();
105 /* Helper class used to construct a pointer to a tuple kind
106 * that refers to a non-template type.
111 /* Construct a pointer to a tuple kind that refers to a non-template type.
113 * Use an empty string as name. Since this is a non-template type,
114 * the kind name will never appear in the generated code.
116 TupleKindPtr::TupleKindPtr(Fixed
) : Base(std::make_shared
<TupleKind
>(""))
120 /* Tuple pointers for non-template types.
122 static TupleKindPtr Ctx
{Fixed()};
123 static TupleKindPtr Integer
{Fixed()};
124 static TupleKindPtr Str
{Fixed()};
125 static TupleKindPtr Res
{Fixed()};
127 /* Special tuple pointers.
128 * Anonymous appears in the generated code but cannot be unified
129 * with anything else since it is a predefined template argument.
130 * Leaf can only be unified with something that is not a pair and
131 * does not appear in the generated code.
133 static TupleKindPtr
Anonymous("Anonymous");
134 static TupleKindPtr
Leaf("Leaf");
136 /* Placeholder tuple pointers that refer to (part of) the domain or range.
138 static TupleKindPtr
Domain("Domain");
139 static TupleKindPtr
Domain2("Domain2");
140 static TupleKindPtr
Domain3("Domain3");
141 static TupleKindPtr
Range("Range");
142 static TupleKindPtr
Range2("Range2");
143 static TupleKindPtr
Range3("Range3");
145 /* A representation of a proper tuple kind that is used as a template
146 * parameter or a template argument.
148 struct ProperTupleKind
: public TupleKind
{
149 ProperTupleKind(const std::string
&name
) : TupleKind(name
) {}
151 virtual std::vector
<std::string
> params() const override
;
154 /* Return the parameters of this tuple kind.
156 * Return the name of this tuple kind, unless it is the special Anonymous
157 * predefined template argument.
159 std::vector
<std::string
> ProperTupleKind::params() const
161 if (Anonymous
.get() == this)
166 /* Construct a pointer to a tuple kind that refers
167 * to a proper tuple kind with the given name.
169 TupleKindPtr::TupleKindPtr(const std::string
&name
) :
170 Base(std::make_shared
<ProperTupleKind
>(name
))
174 /* A tuple kind that represents an anonymous pair of nested tuple kinds.
176 struct Pair
: public TupleKind
{
177 Pair(const TupleKindPtr
&tuple1
, const TupleKindPtr
&tuple2
) :
178 TupleKind(""), tuple1(tuple1
), tuple2(tuple2
) {}
180 virtual std::string
to_string() const override
;
181 virtual std::vector
<std::string
> params() const override
;
182 virtual TupleKindPtr
apply(const Substitution
&match
,
183 const TupleKindPtr
&self
) const override
;
184 virtual TupleKindPtr
left() const override
;
185 virtual TupleKindPtr
right() const override
;
187 const TupleKindPtr tuple1
;
188 const TupleKindPtr tuple2
;
191 /* The textual representation of this tuple kind.
193 * The textual representation of a pair is of the form "pair<tuple1, tuple2>".
195 std::string
Pair::to_string() const
197 return std::string("pair<") + tuple1
->to_string() + ", " +
198 tuple2
->to_string() + ">";
201 /* Add the elements of "vec2" that do not already appear in "vec1"
202 * at the end of "vec1".
204 * The two vectors are assumed not to have any repeated elements.
205 * The updated vector will then also not have repeated elements.
207 static void combine(std::vector
<std::string
> &vec1
,
208 const std::vector
<std::string
> &vec2
)
210 for (const auto &s
: vec2
)
211 if (std::find(vec1
.begin(), vec1
.end(), s
) == vec1
.end())
212 vec1
.emplace_back(s
);
215 /* Return the parameters of this tuple kind.
217 * Combine the parameters of the two nested tuple kinds.
219 std::vector
<std::string
> Pair::params() const
221 auto names1
= tuple1
->params();
222 auto names2
= tuple2
->params();
224 combine(names1
, names2
);
229 /* Apply the substitution "subs" to this tuple kind and return the result.
230 * "self" is a shared pointer to this.
232 * Construct a new tuple kind consisting of the result of applying
233 * the substitution to the two nested tuple kinds.
235 TupleKindPtr
Pair::apply(const Substitution
&subs
, const TupleKindPtr
&self
)
238 return TupleKindPtr(::apply(tuple1
, subs
), ::apply(tuple2
, subs
));
241 /* Return the left child of this tuple kind.
243 TupleKindPtr
Pair::left() const
248 /* Return the right child of this tuple kind.
250 TupleKindPtr
Pair::right() const
255 /* Construct a pointer to a tuple kind that refers
256 * to the given pair of nested tuple kinds.
258 TupleKindPtr::TupleKindPtr(const TupleKindPtr
&left
, const TupleKindPtr
&right
)
259 : Base(std::make_shared
<Pair
>(left
, right
))
263 /* Is this a kind of object representing an anonymous function?
265 bool Kind::is_anon() const
267 return size() != 0 && back() == Anonymous
;
270 /* Is this a kind of object with a single tuple?
272 bool Kind::is_set() const
277 /* Is this a kind of object with a single, anonymous tuple?
279 bool Kind::is_anon_set() const
281 return is_set() && is_anon();
284 /* Return the parameters of this kind.
286 * Collect the parameters of the tuple kinds in the sequence.
288 std::vector
<std::string
> Kind::params() const
290 std::vector
<std::string
> params
;
292 for (const auto &tuple
: *this)
293 combine(params
, tuple
->params());
298 /* Apply the substitution "subs" to this kind and return the result.
300 * Apply the substitution to each of the tuple kinds in the sequence.
302 Kind
Kind::apply(const Substitution
&subs
) const
306 for (const auto &tuple
: *this)
307 applied
.emplace_back(::apply(tuple
, subs
));
312 /* A signature of a method in terms of kinds,
313 * consisting of a return kind and a sequence of argument kinds.
317 std::vector
<Kind
> args
;
319 std::vector
<std::string
> params() const;
320 Signature
apply(const Substitution
&match
) const;
323 /* Return the parameters of this signature.
325 * Collect the parameters of the argument kinds and the return kind.
327 std::vector
<std::string
> Signature::params() const
329 std::vector
<std::string
> params
;
331 for (const auto &arg
: args
)
332 combine(params
, arg
.params());
333 combine(params
, ret
.params());
338 /* Apply the substitution "subs" to this kind and return the result.
340 * Apply the substitution to the argument kinds and the return kind.
342 Signature
Signature::apply(const Substitution
&subs
) const
344 std::vector
<Kind
> applied_args
;
346 for (const auto &arg
: args
)
347 applied_args
.emplace_back(arg
.apply(subs
));
349 return { ret
.apply(subs
), applied_args
};
352 /* Return a renaming substitution that renames the elements of "params"
353 * using names starting with "prefix".
355 static Substitution
param_renamer(const std::vector
<std::string
> ¶ms
,
356 const std::string
&prefix
)
358 Substitution renamer
;
361 for (const auto &name
: params
) {
362 auto suffix
= std::to_string(++n
);
363 auto arg_name
= prefix
+ suffix
;
364 auto arg
= TupleKindPtr(arg_name
);
366 if (name
== Leaf
->name
)
367 generator::die("Leaf cannot be renamed");
369 renamer
.emplace(name
, arg
);
375 /* Does the vector "v" contain the element "el"?
377 static bool contains(const std::vector
<std::string
> &v
, const std::string
&el
)
379 return find(v
.begin(), v
.end(), el
) != v
.end();
383 /* Return the shared elements of "v1" and "v2", preserving the order
384 * of those elements in "v1".
386 static std::vector
<std::string
> intersect(const std::vector
<std::string
> &v1
,
387 const std::vector
<std::string
> &v2
)
389 std::vector
<std::string
> intersection
;
391 for (const auto &el
: v1
)
392 if (contains(v2
, el
))
393 intersection
.push_back(el
);
398 /* Return a renaming substitution that renames
399 * any parameters that appears in both "sig" and "kind".
401 static Substitution
shared_param_renamer(const Signature
&sig
, const Kind
&kind
)
403 return param_renamer(intersect(sig
.params(), kind
.params()), "Arg");
406 /* Signatures for unary operations.
407 * Functions have at least one tuple.
409 static Signature un_params
= { { }, { { } } };
410 static Signature un_set
= { { Domain
}, { { Domain
} } };
411 static Signature un_map
= { { Domain
, Range
}, { { Domain
, Range
} } };
412 static std::vector
<Signature
> un_op
= { un_params
, un_set
, un_map
};
413 static std::vector
<Signature
> fn_un_op
= { un_set
, un_map
};
415 /* Signatures for binary operations, with the second argument
416 * possibly referring to part of the first argument.
417 * Functions have at least one tuple.
419 static Signature bin_params
= { { }, { { }, { } } };
420 static Signature bin_set
= { { Domain
}, { { Domain
}, { Domain
} } };
421 static Signature bin_map
=
422 { { Domain
, Range
}, { { Domain
, Range
}, { Domain
, Range
} } };
423 static std::vector
<Signature
> bin_op
= { bin_params
, bin_set
, bin_map
};
424 static std::vector
<Signature
> fn_bin_op
= { bin_set
, bin_map
};
425 static Signature bin_set_params
= { { Domain
}, { { Domain
}, { } } };
426 static Signature bin_map_params
=
427 { { Domain
, Range
}, { { Domain
, Range
}, { } } };
428 static Signature bin_map_domain
=
429 { { Domain
, Range
}, { { Domain
, Range
}, { Domain
} } };
430 static Signature bin_map_range
=
431 { { Domain
, Range
}, { { Domain
, Range
}, { Range
} } };
432 static Signature bin_map_domain_wrapped_domain
=
433 { { { Domain
, Domain2
}, Range
},
434 { { { Domain
, Domain2
}, Range
}, { Domain
} } };
435 static Signature bin_map_range_wrapped_domain
=
436 { { Domain
, { Range
, Range2
} },
437 { { Domain
, { Range
, Range2
} }, { Range
} } };
439 /* Signatures for binary operations, where the second argument
440 * is an identifier (with an anonymous tuple).
442 static Signature bin_params_anon
= { { }, { { }, { Anonymous
} } };
443 static Signature bin_set_anon
= { { Domain
}, { { Domain
}, { Anonymous
} } };
444 static Signature bin_map_anon
=
445 { { Domain
, Range
}, { { Domain
, Range
}, { Anonymous
} } };
446 static std::vector
<Signature
> bin_op_anon
=
447 { bin_params_anon
, bin_set_anon
, bin_map_anon
};
449 /* Signatures for ternary operations, where the last two arguments are integers.
451 static Signature ter_params_int_int
=
452 { { }, { { }, { Integer
}, { Integer
} } };
453 static Signature ter_set_int_int
=
454 { { Domain
}, { { Domain
}, { Integer
}, { Integer
} } };
455 static Signature ter_map_int_int
=
456 { { Domain
, Range
}, { { Domain
, Range
}, { Integer
}, { Integer
} } };
457 static std::vector
<Signature
> ter_int_int
=
458 { ter_params_int_int
, ter_set_int_int
, ter_map_int_int
};
460 /* Signatures for ternary operations.
461 * Functions have at least one tuple.
463 static Signature ter_set
=
464 { { Domain
}, { { Domain
}, { Domain
}, { Domain
} } };
465 static Signature ter_map
=
467 { { Domain
, Range
}, { Domain
, Range
}, { Domain
, Range
} } };
468 static std::vector
<Signature
> fn_ter_op
= { ter_set
, ter_map
};
470 /* Signatures for naming a leaf tuple using an identifier (with an anonymous
473 static Signature update_set
= { { Domain2
}, { { Leaf
}, { Anonymous
} } };
474 static Signature update_domain
=
475 { { Domain2
, Range
}, { { Leaf
, Range
}, { Anonymous
} } };
476 static Signature update_range
=
477 { { Domain
, Range2
}, { { Domain
, Leaf
}, { Anonymous
} } };
479 /* Signatures for the functions "min" and "max", which can be either
480 * unary or binary operations.
482 static std::vector
<Signature
> min_max
= { un_set
, bin_set
, un_map
, bin_map
};
484 /* Signatures for adding an unnamed tuple to an object with zero or one tuple.
486 static Signature to_set
= { { Domain
}, { { }, { Integer
} } };
487 static Signature add_range
= { { Domain
, Range
}, { { Domain
}, { Integer
} } };
488 /* Signatures for adding a named tuple to an object with zero or one tuple.
490 static Signature to_set_named
=
491 { { Domain
}, { { }, { Anonymous
}, { Integer
} } };
492 static Signature add_range_named
=
493 { { Domain
, Range
}, { { Domain
}, { Anonymous
}, { Integer
} } };
495 /* Signatures for methods applying a map to a set, a function or
498 static Signature set_forward
= { { Range
}, { { Domain
}, { Domain
, Range
} } };
499 static Signature domain_forward
=
500 { { Domain2
, Range
}, { { Domain
, Range
}, { Domain
, Domain2
} } };
501 static Signature range_forward
=
502 { { Domain
, Range2
}, { { Domain
, Range
}, { Range
, Range2
} } };
504 /* Signatures for methods plugging in a function into a set, a function or
507 static Signature set_backward
=
508 { { Domain2
}, { { Domain
}, { Domain2
, Domain
} } };
509 static Signature domain_backward
=
510 { { Domain2
, Range
}, { { Domain
, Range
}, { Domain2
, Domain
} } };
511 static Signature range_backward
=
512 { { Domain
, Range2
}, { { Domain
, Range
}, { Range2
, Range
} } };
513 static Signature domain_wrapped_domain_backward
=
514 { { { Domain3
, Domain2
}, Range
},
515 { { { Domain
, Domain2
}, Range
}, { Domain3
, Domain
} } };
517 /* Signatures for methods binding a set, a function,
518 * or (part of) a map to parameters or an object of the same kind.
520 static Signature bind_set
= { { }, { { Domain
}, { Domain
} } };
521 static Signature bind_domain
= { { Range
}, { { Domain
, Range
}, { Domain
} } };
522 static Signature bind_range
= { { Domain
}, { { Domain
, Range
}, { Range
} } };
523 static Signature bind_domain_wrapped_domain
=
524 { { Range2
, Range
}, { { { Domain2
, Range2
}, Range
}, { Domain2
} } };
526 /* Signatures for functions that take a callback accepting
527 * objects of the same kind (but a different type).
529 * The return and argument kinds of the callback appear
530 * at the position of the callback.
532 static Signature each_params
= { { Res
}, { { }, { Res
}, { } } };
533 static Signature each_set
= { { Res
}, { { Domain
}, { Res
}, { Domain
} } };
534 static Signature each_map
=
535 { { Res
}, { { Domain
, Range
}, { Res
}, { Domain
, Range
} } };
536 static std::vector
<Signature
> each
= { each_params
, each_set
, each_map
};
538 /* Signatures for isl_*_list_foreach_scc.
540 * The first callback takes two elements with the same tuple kinds.
541 * The second callback takes a list with the same tuple kinds.
543 static Signature each_scc_params
=
544 { { Res
}, { { }, { Res
}, { }, { }, { Res
}, { } } };
545 static Signature each_scc_set
=
546 { { Res
}, { { Domain
},
547 { Res
}, { Domain
}, { Domain
},
548 { Res
}, { Domain
} } };
549 static Signature each_scc_map
=
550 { { Res
}, { { Domain
, Range
},
551 { Res
}, { Domain
, Range
}, { Domain
, Range
},
552 { Res
}, { Domain
, Range
} } };
553 static std::vector
<Signature
> each_scc
=
554 { each_scc_params
, each_scc_set
, each_scc_map
};
556 /* Signature for creating a map from a range,
557 * where the domain is given by an extra argument.
559 static Signature map_from_range_and_domain
=
560 { { Domain
, Range
}, { { Range
}, { Domain
} } };
563 /* Signatures for creating a set from a parameter set or
564 * a map from a domain,
565 * where the domain/range is given by an extra argument.
567 static Signature set_from_params
= { { Domain
}, { { }, { Domain
} } };
568 static Signature map_from_domain_and_range
=
569 { { Domain
, Range
}, { { Domain
}, { Range
} } };
570 static std::vector
<Signature
> from_domain
=
571 { set_from_params
, map_from_domain_and_range
};
573 /* Signatures for creating an anonymous set from a parameter set
574 * or a map from a domain, where the range is anonymous.
576 static Signature anonymous_set_from_params
= { { Anonymous
}, { { } } };
577 static Signature anonymous_map_from_domain
=
578 { { Domain
, Anonymous
}, { { Domain
} } };
579 static std::vector
<Signature
> anonymous_from_domain
=
580 { anonymous_set_from_params
, anonymous_map_from_domain
};
582 /* Signatures for creating an anonymous function from a domain,
583 * where the second argument is an identifier (with an anonymous tuple).
585 static Signature anonymous_set_from_params_bin_anon
=
586 { { Anonymous
}, { { }, { Anonymous
} } };
587 static Signature anonymous_map_from_domain_bin_anon
=
588 { { Domain
, Anonymous
}, { { Domain
}, { Anonymous
} } };
589 static std::vector
<Signature
> anonymous_from_domain_bin_anon
= {
590 anonymous_set_from_params_bin_anon
,
591 anonymous_map_from_domain_bin_anon
594 /* Signature for creating a map from a domain,
595 * where the range tuple is equal to the domain tuple.
597 static Signature set_to_map
= { { Domain
, Domain
}, { { Domain
} } };
599 /* Signatures for obtaining the range or the domain of a map.
600 * In case of a transformation, the domain and range are the same.
602 static Signature domain
= { { Domain
}, { { Domain
, Range
} } };
603 static Signature range
= { { Range
}, { { Domain
, Range
} } };
604 static Signature transformation_domain
= { { Domain
}, { { Domain
, Domain
} } };
606 /* Signatures for obtaining the parameter domain of a set or map.
608 static Signature set_params
= { { }, { { Domain
} } };
609 static Signature map_params
= { { }, { { Domain
, Range
} } };
611 /* Signatures for obtaining the domain of a function.
613 static std::vector
<Signature
> fn_domain
= { domain
, set_params
};
615 /* Signatures for interchanging (wrapped) domain and range.
617 static Signature set_reverse
=
618 { { { Range
, Domain
} }, { { { Domain
, Range
} } } };
619 static Signature map_reverse
= { { Range
, Domain
}, { { Domain
, Range
} } };
620 static Signature map_domain_reverse
=
621 { { { Domain2
, Domain
}, Range
}, { { { Domain
, Domain2
}, Range
} } };
622 static Signature map_range_reverse
=
623 { { Domain
, { Range2
, Range
} }, { { Domain
, { Range
, Range2
} } } };
625 /* Signatures for constructing products.
627 static Signature set_product
=
628 { { { Domain
, Range
} }, { { Domain
}, { Range
} } };
629 static Signature map_product
=
630 { { { Domain
, Domain2
}, { Range
, Range2
} },
631 { { Domain
, Range
}, { Domain2
, Range2
} } };
632 static Signature domain_product
=
633 { { { Domain
, Domain2
}, Range
},
634 { { Domain
, Range
}, { Domain2
, Range
} } };
635 static Signature range_product
=
636 { { Domain
, { Range
, Range2
} },
637 { { Domain
, Range
}, { Domain
, Range2
} } };
639 /* Signatures for obtaining factors from a product.
641 static Signature domain_factor_domain
=
642 { { Domain
, Range
}, { { { Domain
, Domain2
}, Range
} } };
643 static Signature domain_factor_range
=
644 { { Domain2
, Range
}, { { { Domain
, Domain2
}, Range
} } };
645 static Signature range_factor_domain
=
646 { { Domain
, Range
}, { { Domain
, { Range
, Range2
} } } };
647 static Signature range_factor_range
=
648 { { Domain
, Range2
}, { { Domain
, { Range
, Range2
} } } };
650 /* Signatures for (un)currying.
652 static Signature curry
=
653 { { Domain
, { Range
, Range2
} },
654 { { { Domain
, Range
}, Range2
} } };
655 static Signature uncurry
=
656 { { { Domain
, Range
}, Range2
},
657 { { Domain
, { Range
, Range2
} } } };
659 /* Signatures for (un)wrapping.
661 static Signature wrap
= { { { Domain
, Range
} }, { { Domain
, Range
} } };
662 static Signature unwrap
= { { Domain
, Range
}, { { { Domain
, Range
} } } };
664 /* Signatures for constructing objects that map to the domain or range
667 static Signature domain_map
=
668 { { { Domain
, Range
}, Domain
}, { { Domain
, Range
} } };
669 static Signature range_map
=
670 { { { Domain
, Range
}, Range
}, { { Domain
, Range
} } };
672 /* Signature for applying a comparison between the domain and the range
675 static Signature map_cmp
=
676 { { Domain
, Domain
}, { { Domain
, Domain
}, { Domain
, Range
} } };
678 /* Signature for creating a set corresponding to the domains
681 static Signature set_join
=
682 { { Domain
}, { { Domain
, Range
}, { Domain
, Range
} } };
684 /* Signatures for flattening the domain or range of a map,
685 * replacing it with either an anonymous tuple or a tuple with a given name.
687 static Signature anonymize_nested_domain
=
688 { { Anonymous
, Range2
}, { { { Domain
, Range
}, Range2
} } };
689 static Signature anonymize_nested_range
=
690 { { Domain
, Anonymous
}, { { Domain
, { Range
, Range2
} } } };
691 static Signature replace_nested_domain
=
692 { { Domain2
, Range2
},
693 { { { Domain
, Range
}, Range2
}, { Anonymous
} } };
694 static Signature replace_nested_range
=
695 { { Domain
, Range3
}, { { Domain
, { Range
, Range2
} }, { Anonymous
} } };
696 static std::vector
<Signature
> flatten_domain
=
697 { anonymize_nested_domain
, replace_nested_domain
};
698 static std::vector
<Signature
> flatten_range
=
699 { anonymize_nested_range
, replace_nested_range
};
701 /* Signatures for "set_at" methods.
703 static Signature set_at_set
=
704 { { Domain
}, { { Domain
}, { Integer
}, { Anonymous
} } };
705 static Signature set_at_map
=
707 { { Domain
, Range
}, { Integer
}, { Domain
, Anonymous
} } };
708 static std::vector
<Signature
> set_at
= { set_at_set
, set_at_map
};
710 /* Signatures for "list" methods, extracting a list
711 * from a multi-expression.
713 static Signature to_list_set
= { { Anonymous
}, { { Domain
} } };
714 static Signature to_list_map
= { { Domain
, Anonymous
}, { { Domain
, Range
} } };
716 /* Signatures for functions constructing an object from only an isl::ctx.
718 static Signature ctx_params
= { { }, { { Ctx
} } };
719 static Signature ctx_set
= { { Domain
}, { { Ctx
} } };
720 static Signature ctx_map
= { { Domain
, Range
}, { { Ctx
} } };
722 /* Helper structure for sorting the keys of static_methods and
723 * special_member_methods such that the larger keys appear first.
724 * In particular, a key should appear before any key that appears
725 * as a substring in the key.
726 * Note that this sorting is currently only important
727 * for special_member_methods.
729 struct larger_infix
{
730 bool operator()(const std::string
&x
, const std::string
&y
) const {
731 if (x
.length() > y
. length())
737 /* A map from part of a type name to a sequence of signatures.
739 typedef std::map
<std::string
, std::vector
<Signature
>, larger_infix
> infix_map
;
741 /* A map from a method name to a map from part of a type name
742 * to a sequence of signatures.
744 typedef std::map
<std::string
, infix_map
> infix_map_map
;
746 /* Signatures for static methods.
748 * The "unit" static method is only available in a 0-tuple space.
750 * The "empty" static method creates union objects with the relevant
753 * The "universe" static methods create objects from the corresponding spaces.
755 static const infix_map_map static_methods
{
757 { { "space", { ctx_params
} } }
761 { "union_set", { ctx_params
, ctx_set
} },
762 { "union_map", { ctx_map
} },
763 { "union_pw_multi_aff", { ctx_set
, ctx_map
} },
768 { "set", { un_params
, un_set
} },
769 { "map", { un_map
} },
774 /* Signatures for unary operations that either take something in a set space
775 * and return something in the same space or take something in a map space
776 * and return something in the range of that space.
778 static std::vector
<Signature
> range_op
= { un_set
, range
};
780 /* Signatures for binary operations where the second argument
781 * is a (multi-)value.
783 static std::vector
<Signature
> bin_val
= { bin_set
, bin_map_range
};
785 /* The (default) signatures for methods with a given name.
786 * Some of these are overridden by special_member_methods.
788 static const std::unordered_map
<std::string
, std::vector
<Signature
>>
791 { "add_constant", bin_val
},
792 { "add_named_tuple", { to_set_named
, add_range_named
} },
793 { "add_param", bin_op_anon
},
794 { "add_unnamed_tuple", { to_set
, add_range
} },
795 { "apply", { set_forward
, range_forward
} },
796 { "apply_domain", { domain_forward
} },
797 { "apply_range", { range_forward
} },
799 { "as_map", { un_map
} },
800 { "as_union_map", { un_map
} },
801 { "as_set", { un_set
} },
802 { "bind", { bind_set
, bind_range
} },
803 { "bind_domain", { bind_domain
} },
804 { "bind_range", { bind_range
} },
805 { "bind_domain_wrapped_domain",
806 { bind_domain_wrapped_domain
} },
807 { "ceil", fn_un_op
},
808 { "coalesce", un_op
},
809 { "cond", fn_ter_op
},
810 { "constant", range_op
},
811 { "curry", { curry
} },
812 { "deltas", { transformation_domain
} },
813 { "detect_equalities", un_op
},
814 { "domain", fn_domain
},
815 { "domain_factor_domain",
816 { domain_factor_domain
} },
817 { "domain_factor_range",
818 { domain_factor_range
} },
819 { "domain_map", { domain_map
} },
820 { "domain_product", { domain_product
} },
821 { "domain_reverse", { map_domain_reverse
} },
822 { "drop", ter_int_int
},
823 { "drop_all_params", un_op
},
824 { "drop_unused_params", un_op
},
825 { "eq_at", { map_cmp
} },
827 { "extract", bin_op
},
828 { "flatten_domain", flatten_domain
},
829 { "flatten_range", flatten_range
},
830 { "floor", fn_un_op
},
832 { "foreach_scc", each_scc
},
833 { "ge_set", { set_join
} },
834 { "gt_set", { set_join
} },
836 { "gist_domain", { bin_map_domain
} },
837 { "gist_params", { bin_set_params
, bin_map_params
} },
838 { "identity", { un_map
, set_to_map
} },
839 { "identity_on_domain", { set_to_map
} },
840 { "indicator_function", anonymous_from_domain
},
841 { "insert_domain", { map_from_range_and_domain
} },
842 { "intersect", bin_op
},
843 { "intersect_params", { bin_set_params
, bin_map_params
} },
844 { "intersect_domain", { bin_map_domain
} },
845 { "intersect_domain_wrapped_domain",
846 { bin_map_domain_wrapped_domain
} },
847 { "intersect_range", { bin_map_range
} },
848 { "intersect_range_wrapped_domain",
849 { bin_map_range_wrapped_domain
} },
850 { "lattice_tile", { un_set
} },
851 { "le_set", { set_join
} },
852 { "lt_set", { set_join
} },
853 { "lex_le_at", { map_cmp
} },
854 { "lex_lt_at", { map_cmp
} },
855 { "lex_ge_at", { map_cmp
} },
856 { "lex_gt_at", { map_cmp
} },
857 { "lexmin", fn_un_op
},
858 { "lexmax", fn_un_op
},
859 { "list", { to_list_set
, to_list_map
} },
860 { "lower_bound", fn_bin_op
},
861 { "map_from_set", { set_to_map
} },
863 { "max_val", range_op
},
864 { "max_multi_val", range_op
},
866 { "min_val", range_op
},
867 { "min_multi_val", range_op
},
869 { "on_domain", from_domain
},
871 { "offset", fn_un_op
},
872 { "param_on_domain", anonymous_from_domain_bin_anon
},
873 { "params", { set_params
, map_params
} },
874 { "plain_multi_val_if_fixed",
876 { "preimage", { set_backward
} },
877 { "preimage_domain", { domain_backward
} },
878 { "preimage_domain_wrapped_domain",
879 { domain_wrapped_domain_backward
} },
880 { "preimage_range", { range_backward
} },
881 { "product", { set_product
, map_product
} },
882 { "project_out_param", bin_op_anon
},
883 { "project_out_all_params",
885 { "pullback", { domain_backward
, bind_domain
} },
886 { "range", { range
} },
887 { "range_factor_domain",
888 { range_factor_domain
} },
889 { "range_factor_range", { range_factor_range
} },
890 { "range_lattice_tile", { un_map
} },
891 { "range_map", { range_map
} },
892 { "range_product", { range_product
} },
893 { "range_reverse", { map_range_reverse
} },
894 { "range_simple_fixed_box_hull",
896 { "reverse", { map_reverse
} },
897 { "scale", bin_val
},
898 { "scale_down", bin_val
},
899 { "set_at", set_at
},
900 { "set_domain_tuple", { update_domain
} },
901 { "set_range_tuple", { update_set
, update_range
} },
902 { "simple_fixed_box_hull",
904 { "sub", fn_bin_op
},
905 { "subtract", bin_op
},
906 { "subtract_domain", { bin_map_domain
} },
907 { "subtract_range", { bin_map_range
} },
908 { "translation", { set_to_map
} },
910 { "unbind_params", { set_from_params
} },
911 { "unbind_params_insert_domain",
912 { map_from_range_and_domain
} },
913 { "uncurry", { uncurry
} },
914 { "union_add", fn_bin_op
},
916 { "universe", un_op
},
917 { "unwrap", { unwrap
} },
918 { "upper_bound", fn_bin_op
},
919 { "wrap", { wrap
} },
920 { "wrapped_reverse", { set_reverse
} },
921 { "zero", fn_un_op
},
922 { "zero_on_domain", { anonymous_map_from_domain
} },
925 /* Signatures for constructors of multi-expressions
926 * from a space and a list, with a special case for multi-union-expressions.
928 static Signature from_list_set
= { { Domain
}, { { Domain
}, { Anonymous
} } };
929 static Signature from_list_map
=
930 { { Domain
, Range
}, { { Domain
, Range
}, { Domain
, Anonymous
} } };
931 static Signature from_list_map_union
=
932 { { Domain
, Range
}, { { Range
}, { Domain
, Anonymous
} } };
934 /* Signatures for methods of types containing a given substring
935 * that override the default signatures, where larger substrings
938 * In particular, "gist" is usually a regular binary operation,
939 * but for any type derived from "aff", the argument refers
940 * to the domain of the function.
942 * When constructing a multi-expression from a space and a list,
943 * the kind of the space is usually the same as that of
944 * the constructed multi-expression. However, if the constructed object
945 * is a multi-union-expression, then the space is the fixed range space
946 * of the multi-union-expression, so it always has a single tuple.
947 * This happens in particular for constructing objects
948 * of type "multi_union_pw_aff".
949 * See also the "space" method below.
951 * The "size" method can usually simply be inherited from
952 * the corresponding plain C++ type, but for a "fixed_box",
953 * the size lives in the space of the box or its range.
955 * The "space" method is usually a regular unary operation
956 * that returns the single space of the elements in the object,
957 * with the same number of tuples.
958 * However, a "union" object may contain elements from many spaces and
959 * therefore its space only refers to the symbolic constants and
960 * has zero tuples, except if it is also a "multi_union" object,
961 * in which case it has a fixed range space and the space of the object
962 * has a single tuple.
963 * Note that since "space' is also the name of a template class,
964 * the default space method is handled by print_type_named_member_method.
966 static const infix_map_map special_member_methods
{
968 { { "aff", { bin_set_params
, bin_map_domain
} } }
970 { "multi_union_pw_aff",
971 { { "space", { from_list_set
, from_list_map_union
} } }
974 { { "fixed_box", range_op
} },
978 { "multi_union", range_op
},
979 { "union", { un_params
, set_params
, map_params
} },
984 /* Generic kinds for objects with zero, one or two tuples,
985 * the last of which may be anonymous.
987 static Kind params
{};
988 static Kind set_type
{ Domain
};
989 static Kind set_anon
{ Anonymous
};
990 static Kind map_type
{ Domain
, Range
};
991 static Kind map_anon
{ Domain
, Anonymous
};
993 /* The initial sequence of specialization kinds for base types.
994 * The specialization kinds for other types are derived
995 * from the corresponding base types.
997 * In particular, this sequence specifies how many tuples
998 * a given type can have and whether it is anonymous.
1000 * "space" can have any number of tuples.
1001 * "set" and "point" can have zero or one tuple.
1002 * "map" can only have two tuples.
1003 * "aff" can have one or two tuples, the last of which is anonymous.
1004 * "fixed_box" can represent a (proper) set) or a map.
1005 * "val" and "id" are treated as anonymous sets so that
1006 * they can form the basis of "multi_val" and "multi_id".
1008 static const std::unordered_map
<std::string
, std::vector
<Kind
>> base_kinds
{
1009 { "space", { params
, set_type
, map_type
} },
1010 { "set", { params
, set_type
} },
1011 { "point", { params
, set_type
} },
1012 { "map", { map_type
} },
1013 { "aff", { set_anon
, map_anon
} },
1014 { "fixed_box", { set_type
, map_type
} },
1015 { "val", { set_anon
} },
1016 { "id", { set_anon
} },
1019 /* Prefixes introduced by type constructors.
1021 static const std::unordered_set
<std::string
> type_prefixes
{
1028 /* If "type" has a "_list" suffix, then return "type" with this suffix removed.
1029 * Otherwise, simply return "type".
1031 static std::string
drop_list(const std::string
&type
)
1033 size_t pos
= type
.rfind('_');
1035 if (pos
== std::string::npos
)
1037 if (type
.substr(pos
+ 1) == "list")
1038 return type
.substr(0, pos
);
1042 /* Given the name of a plain C++ type, return the base type
1043 * from which it was derived using type constructors.
1045 * In particular, drop any "list" suffix and
1046 * drop any prefixes from type_prefixes, stopping
1047 * as soon as a base type is found for which kinds have been registered
1050 static std::string
base_type(const std::string
&type
)
1055 base
= drop_list(base
);
1056 while (base_kinds
.count(base
) == 0 &&
1057 (pos
= base
.find('_')) != std::string::npos
&&
1058 type_prefixes
.count(base
.substr(0, pos
)) != 0) {
1059 base
= base
.substr(pos
+ 1);
1065 /* A mapping from anonymous kinds to named kinds.
1067 static std::map
<Kind
, Kind
> anon_to_named
{
1068 { set_anon
, set_type
},
1069 { map_anon
, map_type
},
1072 /* Given a sequence of anonymous kinds, replace them
1073 * by the corresponding named kinds.
1075 static std::vector
<Kind
> add_name(const std::vector
<Kind
> &tuples
)
1077 std::vector
<Kind
> named
;
1079 for (const auto &tuple
: tuples
)
1080 named
.emplace_back(anon_to_named
.at(tuple
));
1085 /* Look up the (initial) specializations of the class called "name".
1086 * If no specializations have been defined, then return an empty vector.
1088 * Start from the initial specializations of the corresponding base type.
1089 * If this template class is a multi-expression, then it was derived
1090 * from an anonymous function type. Replace the final Anonymous
1091 * tuple kind by a placeholder in this case.
1093 static std::vector
<Kind
> lookup_class_tuples(const std::string
&name
)
1095 std::string base
= base_type(name
);
1097 if (base_kinds
.count(base
) == 0)
1099 if (name
.find("multi_") != std::string::npos
)
1100 return add_name(base_kinds
.at(base
));
1101 return base_kinds
.at(base
);
1104 /* Add a template class called "name", of which the methods are described
1105 * by "clazz" and the initial specializations by "class_tuples".
1107 void template_cpp_generator::add_template_class(const isl_class
&clazz
,
1108 const std::string
&name
, const std::vector
<Kind
> &class_tuples
)
1110 auto isl_namespace
= cpp_type_printer().isl_namespace();
1111 auto super
= isl_namespace
+ name
;
1113 template_classes
.emplace(name
,
1114 template_class
{name
, super
, clazz
, class_tuples
});
1117 /* Construct a templated C++ bindings generator from
1118 * the exported types and functions and the set of all declared functions.
1120 * On top of the initialization of the shared parts
1121 * of C++ bindings generators, add a template class
1122 * for each plain C++ class for which template kinds
1123 * have been defined.
1124 * In particular, determine the base type from which the plain C++ class
1125 * was derived using type constructors and check if any template kinds
1126 * have been registered for this base type.
1128 template_cpp_generator::template_cpp_generator(clang::SourceManager
&SM
,
1129 std::set
<clang::RecordDecl
*> &exported_types
,
1130 std::set
<clang::FunctionDecl
*> exported_functions
,
1131 std::set
<clang::FunctionDecl
*> functions
) :
1132 cpp_generator(SM
, exported_types
, exported_functions
,
1135 for (const auto &kvp
: classes
) {
1136 const auto &clazz
= kvp
.second
;
1137 std::string name
= type2cpp(clazz
);
1138 const auto &class_tuples
= lookup_class_tuples(name
);
1140 if (class_tuples
.empty())
1142 add_template_class(clazz
, name
, class_tuples
);
1146 /* Call "fn" on each template class.
1148 void template_cpp_generator::foreach_template_class(
1149 const std::function
<void(const template_class
&)> &fn
) const
1151 for (const auto &kvp
: template_classes
)
1155 /* Print forward declarations for all template classes to "os".
1157 * For template classes that represent an anonymous function
1158 * that can also have a domain tuple, provide an <name>_on alias
1159 * that adds the fixed Anonymous tuple kind.
1161 void template_cpp_generator::print_forward_declarations(std::ostream
&os
)
1163 foreach_template_class([&os
] (const template_class
&template_class
) {
1164 auto name
= template_class
.class_name
;
1167 os
<< "template <typename...>\n";
1168 os
<< "struct " << name
<< ";\n";
1170 if (!template_class
.is_anon())
1172 if (template_class
.is_anon_set())
1176 os
<< "template <typename...Ts>\n";
1177 os
<< "using " << name
<< "_on = "
1178 << name
<< "<Ts..., Anonymous>;\n";
1182 /* Print friend declarations for all template classes to "os".
1184 void template_cpp_generator::print_friends(std::ostream
&os
)
1186 foreach_template_class([&os
] (const template_class
&template_class
) {
1187 os
<< " template <typename...>\n";
1188 os
<< " friend struct " << template_class
.class_name
<< ";\n";
1192 /* Print a template parameter or argument.
1193 * In case of a std::string, it's a template parameter
1194 * that needs to be declared.
1196 static void print_template_arg(std::ostream
&os
, const std::string
&arg
)
1198 os
<< "typename " << arg
;
1201 /* Print a template parameter or argument.
1202 * In case of a TupleKindPtr, it's a template argument.
1204 static void print_template_arg(std::ostream
&os
, const TupleKindPtr
&kind
)
1206 os
<< kind
->to_string();
1209 /* Print a sequence of template parameters (std::string) or
1210 * arguments (TupleKindPtr) "args", without the enclosing angle brackets.
1212 template <typename List
>
1213 static void print_pure_template_args(std::ostream
&os
, const List
&args
)
1215 for (size_t i
= 0; i
< args
.size(); ++i
) {
1218 print_template_arg(os
, args
[i
]);
1222 /* Print a sequence of template parameters (std::string) or
1223 * arguments (TupleKindPtr) "args".
1225 template <typename List
>
1226 static void print_template_args(std::ostream
&os
, const List
&args
)
1229 print_pure_template_args(os
, args
);
1233 /* Print a declaration of the template parameters "params".
1235 static void print_template(std::ostream
&os
,
1236 const std::vector
<std::string
> ¶ms
)
1239 print_template_args(os
, params
);
1243 /* Print a declaration of the template parameters "params",
1246 static void print_non_empty_template(std::ostream
&os
,
1247 const std::vector
<std::string
> ¶ms
)
1249 if (params
.size() > 0)
1250 print_template(os
, params
);
1253 /* Print a bare template type, i.e., without namespace,
1254 * consisting of the type "type" and the kind "kind" to "os".
1256 * In particular, print "type" followed by the template arguments
1257 * as specified by "kind".
1259 static void print_bare_template_type(std::ostream
&os
, const std::string
&type
,
1263 print_template_args(os
, kind
);
1266 /* A specific instance of "template_class", with tuple kinds given by "kind".
1268 struct specialization
{
1269 struct template_class
&template_class
;
1272 const std::string
&base_name() const;
1273 const std::string
&class_name() const;
1276 /* The name of the plain C++ interface class
1277 * from which this template class (instance) derives.
1279 const std::string
&specialization::base_name() const
1281 return template_class
.super_name
;
1284 /* The name of the template class.
1286 const std::string
&specialization::class_name() const
1288 return template_class
.class_name
;
1291 /* Helper class for printing the specializations of template classes
1292 * that is used to print both the class declarations and the class definitions.
1294 * "os" is the stream onto which the classes should be printed.
1295 * "generator" is the templated C++ interface generator printing the classes.
1297 struct specialization_printer
{
1298 specialization_printer(std::ostream
&os
,
1299 template_cpp_generator
&generator
) :
1300 os(os
), generator(generator
) {}
1302 virtual void print_class(const specialization
&instance
) const = 0;
1303 void print_classes() const;
1306 template_cpp_generator
&generator
;
1309 /* Print all specializations of all template classes.
1311 * Each class has a predefined set of initial specializations,
1312 * but while such a specialization is being printed,
1313 * the need for other specializations may arise and
1314 * these are added at the end of the list of specializations.
1315 * That is, class_tuples.size() may change during the execution
1318 * For each specialization of a template class, call
1319 * the print_class virtual method.
1321 void specialization_printer::print_classes() const
1323 for (auto &kvp
: generator
.template_classes
) {
1324 auto &template_class
= kvp
.second
;
1325 const auto &class_tuples
= template_class
.class_tuples
;
1327 for (size_t i
= 0; i
< class_tuples
.size(); ++i
)
1328 print_class({ template_class
, class_tuples
[i
] });
1332 /* A helper class for printing method declarations and definitions
1333 * of a template class specialization.
1335 * "instance" is the template class specialization for which methods
1337 * "generator" is the templated C++ interface generator printing the classes.
1339 struct template_cpp_generator::class_printer
:
1340 public cpp_generator::class_printer
{
1341 class_printer(const specialization
&instance
,
1342 const specialization_printer
&instance_printer
,
1343 bool is_declaration
);
1345 void print_return_type(const Method
&method
, const Kind
&kind
)
1347 void print_method_template_arguments(const Signature
&sig
);
1348 void print_method_header(const Method
&method
, const Signature
&sig
);
1349 bool print_special_method(const Method
&method
,
1350 const infix_map_map
&special_methods
);
1351 void print_static_method(const Method
&method
);
1352 void print_constructor(const Method
&method
);
1353 bool is_return_kind(const Method
&method
, const Kind
&return_kind
);
1354 void add_specialization(const Kind
&kind
);
1355 bool print_matching_method(const Method
&method
, const Signature
&sig
,
1356 const Kind
&match_arg
);
1357 bool print_matching_method(const Method
&method
, const Signature
&sig
);
1358 void print_matching_method(const Method
&method
,
1359 const std::vector
<Signature
> &signatures
);
1360 void print_at_method(const Method
&method
);
1361 bool print_special_member_method(const Method
&method
);
1362 bool print_type_named_member_method(const Method
&method
);
1363 bool print_member_method_with_name(const Method
&method
,
1364 const std::string
&name
);
1365 void print_member_method(const Method
&method
);
1366 void print_any_method(const Method
&method
);
1367 virtual void print_method(const Method
&method
) override
;
1368 virtual void print_method(const ConversionMethod
&method
) override
;
1369 virtual void print_method_sig(const Method
&method
,
1370 const Signature
&sig
, bool deleted
) = 0;
1371 virtual bool want_descendent_overloads(const function_set
&methods
)
1373 void print_all_methods();
1375 const specialization
&instance
;
1376 template_cpp_generator
&generator
;
1379 /* Construct a class_printer from the template class specialization
1380 * for which methods are printed and
1381 * the printer of the template class.
1383 * The template class printer is only used to obtain the output stream and
1384 * the templated C++ interface generator printing the classes.
1386 template_cpp_generator::class_printer::class_printer(
1387 const specialization
&instance
,
1388 const specialization_printer
&instance_printer
,
1389 bool is_declaration
) :
1390 cpp_generator::class_printer(instance_printer
.os
,
1391 instance
.template_class
.clazz
, instance_printer
.generator
,
1393 instance(instance
), generator(instance_printer
.generator
)
1397 /* An abstract template type printer, where the way of obtaining
1398 * the argument kind is specified by the subclasses.
1400 struct template_cpp_type_printer
: public cpp_type_printer
{
1401 template_cpp_type_printer() {}
1403 std::string
base(const std::string
&type
, const Kind
&kind
) const;
1404 virtual Kind
kind(int arg
) const = 0;
1405 virtual std::string
qualified(int arg
, const std::string
&cpp_type
)
1409 /* Print a template type consisting of the type "type" and the kind "kind",
1410 * including the "typed::" namespace specifier.
1412 std::string
template_cpp_type_printer::base(const std::string
&type
,
1413 const Kind
&kind
) const
1415 std::ostringstream ss
;
1418 print_bare_template_type(ss
, type
, kind
);
1422 /* Return the qualified form of the given C++ isl type name appearing
1423 * in argument position "arg" (-1 for return type).
1425 * isl::ctx is not templated, so if "cpp_type" is "ctx",
1426 * then print a non-templated version.
1427 * Otherwise, look up the kind of the argument and print
1428 * the corresponding template type.
1430 std::string
template_cpp_type_printer::qualified(int arg
,
1431 const std::string
&cpp_type
) const
1433 if (cpp_type
== "ctx")
1434 return cpp_type_printer::qualified(arg
, cpp_type
);
1436 return base(cpp_type
, kind(arg
));
1439 /* A template type printer for printing types with a fixed kind.
1441 * "fixed_kind" is the fixed kind.
1443 struct template_cpp_kind_type_printer
: public template_cpp_type_printer
{
1444 template_cpp_kind_type_printer(const Kind
&kind
) :
1445 template_cpp_type_printer(), fixed_kind(kind
) {}
1447 virtual Kind
kind(int arg
) const override
;
1449 const Kind
&fixed_kind
;
1452 /* Return the kind of the argument at position "arg",
1453 * where position -1 refers to the return type.
1455 * Always use the fixed kind.
1457 Kind
template_cpp_kind_type_printer::kind(int arg
) const
1462 /* A template type printer for printing a method with a given signature.
1464 * "sig" is the signature of the method being printed.
1466 struct template_cpp_arg_type_printer
: public template_cpp_type_printer
{
1467 template_cpp_arg_type_printer(const Signature
&sig
) :
1468 template_cpp_type_printer(), sig(sig
) {}
1470 virtual Kind
kind(int arg
) const override
;
1472 const Signature
&sig
;
1475 /* Return the kind of the argument at position "arg",
1476 * where position -1 refers to the return type.
1478 * Look up the kind in the signature.
1480 Kind
template_cpp_arg_type_printer::kind(int arg
) const
1482 int n_args
= sig
.args
.size();
1487 generator::die("argument out of bounds");
1488 return sig
.args
[arg
];
1491 /* A template type printer for printing a method with a given signature
1492 * as part of a template class specialization of a given kind.
1494 * "class_kind" is the template class specialization kind.
1496 struct template_method_type_printer
: public template_cpp_arg_type_printer
{
1497 template_method_type_printer(const Signature
&sig
,
1498 const Kind
&class_kind
) :
1499 template_cpp_arg_type_printer(sig
),
1500 class_kind(class_kind
) {}
1502 virtual std::string
class_type(const std::string
&cpp_name
)
1505 const Kind
&class_kind
;
1508 /* Print the class type "cpp_name".
1510 * Print the templated version using the template class specialization kind.
1512 std::string
template_method_type_printer::class_type(
1513 const std::string
&cpp_name
) const
1515 return base(cpp_name
, class_kind
);
1518 /* Print the templated return type of "method" of the kind "return_kind".
1520 * Construct a type printer with "return_kind" as fixed kind and
1521 * use it to print the return type.
1523 void template_cpp_generator::class_printer::print_return_type(
1524 const Method
&method
, const Kind
&return_kind
) const
1526 template_cpp_kind_type_printer
printer(return_kind
);
1528 os
<< printer
.return_type(method
);
1531 /* Remove the initial "n" elements from "v".
1533 template <typename T
>
1534 static void drop_initial(std::vector
<T
> &v
, size_t n
)
1536 v
.erase(v
.begin(), v
.begin() + n
);
1539 /* If a method with signature "sig" requires additional template parameters
1540 * compared to those of the class, then print a declaration for them.
1541 * If this->declarations is set, then this will be part of a method declaration,
1542 * requiring extra indentation.
1544 * Construct the sequence of all required template parameters
1545 * with those of the template class appearing first.
1546 * If this sequence has any parameters not induced by the template class itself,
1547 * then print a declaration for these extra parameters.
1549 void template_cpp_generator::class_printer::print_method_template_arguments(
1550 const Signature
&sig
)
1552 std::vector
<std::string
> class_params
, method_params
;
1554 class_params
= instance
.kind
.params();
1555 method_params
= class_params
;
1556 combine(method_params
, sig
.params());
1558 if (class_params
.size() == method_params
.size())
1561 drop_initial(method_params
, class_params
.size());
1565 print_template(os
, method_params
);
1568 /* Print the header for "method" with signature "sig".
1570 * First print any additional template parameters that may be required and
1571 * then print a regular method header, using a template type printer.
1573 void template_cpp_generator::class_printer::print_method_header(
1574 const Method
&method
, const Signature
&sig
)
1576 template_method_type_printer
type_printer(sig
, instance
.kind
);
1578 print_method_template_arguments(sig
);
1579 cpp_generator::class_printer::print_method_header(method
,
1583 /* Given a group of methods with the same name,
1584 * should extra methods be added that take as arguments
1585 * those types that can be converted to the original argument type
1586 * through a unary constructor?
1588 * Since type deduction does not consider implicit conversions,
1589 * these extra methods should always be printed.
1591 bool template_cpp_generator::class_printer::want_descendent_overloads(
1592 const function_set
&methods
)
1597 /* Print all constructors and methods that forward
1598 * to the corresponding methods in the plain C++ interface class.
1600 void template_cpp_generator::class_printer::print_all_methods()
1602 print_constructors();
1606 /* A helper class for printing method declarations
1607 * of a template class specialization.
1609 struct template_cpp_generator::method_decl_printer
:
1610 public template_cpp_generator::class_printer
{
1611 method_decl_printer(const specialization
&instance
,
1612 const struct specialization_printer
&instance_printer
) :
1613 class_printer(instance
, instance_printer
, true) {}
1615 virtual void print_method_sig(const Method
&method
,
1616 const Signature
&sig
, bool deleted
) override
;
1617 virtual void print_get_method(FunctionDecl
*fd
) override
;
1620 /* Print a declaration of the method "method" with signature "sig".
1621 * Mark is "delete" if "deleted" is set.
1623 void template_cpp_generator::method_decl_printer::print_method_sig(
1624 const Method
&method
, const Signature
&sig
, bool deleted
)
1626 print_method_header(method
, sig
);
1632 /* Return the total number of arguments in the signature for "method",
1633 * taking into account any possible callback arguments.
1635 * In particular, if the method has a callback argument,
1636 * then the return kind of the callback appears at the position
1637 * of the callback and the kinds of the arguments (except
1638 * the user pointer argument) appear in the following positions.
1639 * The user pointer argument that follows the callback argument
1642 static int total_params(const Method
&method
)
1644 int n
= method
.num_params();
1646 for (const auto &callback
: method
.callbacks
) {
1647 auto callback_type
= callback
->getType();
1648 auto proto
= generator::extract_prototype(callback_type
);
1650 n
+= proto
->getNumArgs() - 1;
1657 /* Return a signature for "method" that matches "instance".
1659 static Signature
instance_sig(const Method
&method
,
1660 const specialization
&instance
)
1662 std::vector
<Kind
> args(total_params(method
));
1664 args
[0] = instance
.kind
;
1665 return { instance
.kind
, args
};
1668 /* Print a declaration for the "get" method "fd",
1669 * using a name that includes the "get_" prefix.
1671 * These methods are only included in the plain interface.
1672 * Explicitly delete them from the templated interface.
1674 void template_cpp_generator::method_decl_printer::print_get_method(
1677 Method
method(clazz
, fd
, clazz
.base_method_name(fd
));
1679 print_method_sig(method
, instance_sig(method
, instance
), true);
1682 /* A helper class for printing method definitions
1683 * of a template class specialization.
1685 struct template_cpp_generator::method_impl_printer
:
1686 public template_cpp_generator::class_printer
{
1687 method_impl_printer(const specialization
&instance
,
1688 const struct specialization_printer
&instance_printer
) :
1689 class_printer(instance
, instance_printer
, false) {}
1691 void print_callback_method_body(const Method
&method
,
1692 const Signature
&sig
);
1693 void print_method_body(const Method
&method
, const Signature
&sig
);
1694 void print_constructor_body(const Method
&method
, const Signature
&sig
);
1695 virtual void print_method_sig(const Method
&method
,
1696 const Signature
&sig
, bool deleted
) override
;
1697 virtual void print_get_method(FunctionDecl
*fd
) override
;
1700 /* Print a definition of the constructor "method" with signature "sig".
1702 * Simply pass all arguments to the constructor of the corresponding
1705 void template_cpp_generator::method_impl_printer::print_constructor_body(
1706 const Method
&method
, const Signature
&sig
)
1708 const auto &base_name
= instance
.base_name();
1710 os
<< " : " << base_name
;
1711 method
.print_cpp_arg_list(os
, [&] (int i
, int arg
) {
1712 os
<< method
.fd
->getParamDecl(i
)->getName().str();
1720 /* Print the arguments of the callback function "callback" to "os",
1721 * calling "print_arg" with the type and the name of the arguments,
1722 * where the type is obtained from "type_printer" with argument positions
1723 * shifted by "shift".
1724 * None of the arguments should be skipped.
1726 static void print_callback_args(std::ostream
&os
,
1727 const FunctionProtoType
*callback
, const cpp_type_printer
&type_printer
,
1729 const std::function
<void(const std::string
&type
,
1730 const std::string
&name
)> &print_arg
)
1732 auto n_arg
= callback
->getNumArgs() - 1;
1734 Method::print_arg_list(os
, 0, n_arg
, [&] (int i
) {
1735 auto type
= callback
->getArgType(i
);
1736 auto name
= "arg" + std::to_string(i
);
1737 auto cpptype
= type_printer
.param(shift
+ i
, type
);
1739 print_arg(cpptype
, name
);
1745 /* Print a lambda corresponding to "callback"
1746 * with signature "sig" and argument positions shifted by "shift".
1748 * The lambda takes arguments with plain isl types and
1749 * calls the callback of "method" with templated arguments.
1751 static void print_callback_lambda(std::ostream
&os
, ParmVarDecl
*callback
,
1752 const Signature
&sig
, int shift
)
1754 auto callback_type
= callback
->getType();
1755 auto callback_name
= callback
->getName().str();
1756 auto proto
= generator::extract_prototype(callback_type
);
1758 os
<< " auto lambda_" << callback_name
<< " = [&] ";
1759 print_callback_args(os
, proto
, cpp_type_printer(), shift
,
1760 [&] (const std::string
&type
, const std::string
&name
) {
1761 os
<< type
<< " " << name
;
1765 os
<< " return " << callback_name
;
1766 print_callback_args(os
, proto
, template_cpp_arg_type_printer(sig
),
1768 [&] (const std::string
&type
, const std::string
&name
) {
1769 os
<< type
<< "(" << name
<< ")";
1776 /* Print lambdas for passing to the plain method corresponding to "method"
1777 * with signature "sig".
1779 * The method is assumed to have only callbacks as argument,
1780 * which means the arguments of the first callback are shifted by 2
1781 * with respect to the arguments of the signature
1782 * (one for the position of the callback argument plus
1783 * one for the return kind of the callback).
1784 * The arguments of a subsequent callback are shifted by
1785 * the number of arguments of the previous callback minus one
1786 * for the user pointer plus one for the return kind.
1788 static void print_callback_lambdas(std::ostream
&os
, const Method
&method
,
1789 const Signature
&sig
)
1793 if (method
.num_params() != 1 + 2 * method
.callbacks
.size())
1794 generator::die("callbacks are assumed to be only arguments");
1797 for (const auto &callback
: method
.callbacks
) {
1798 print_callback_lambda(os
, callback
, sig
, shift
);
1799 shift
+= generator::prototype_n_args(callback
->getType());
1803 /* Print a definition of the member method "method", which is known
1804 * to have a callback argument, with signature "sig".
1806 * First print lambdas for passing to the corresponding plain method and
1807 * calling the callback of "method" with templated arguments.
1808 * Then call the plain method, replacing the original callbacks
1811 * The return value is assumed to be isl_bool or isl_stat
1812 * so that no conversion to a template type is required.
1814 void template_cpp_generator::method_impl_printer::print_callback_method_body(
1815 const Method
&method
, const Signature
&sig
)
1817 const auto &base_name
= instance
.base_name();
1818 auto return_type
= method
.fd
->getReturnType();
1820 if (!is_isl_bool(return_type
) && !is_isl_stat(return_type
))
1821 die("only isl_bool and isl_stat return types are supported");
1825 print_callback_lambdas(os
, method
, sig
);
1828 os
<< base_name
<< "::" << method
.name
;
1829 method
.print_cpp_arg_list(os
, [&] (int i
, int arg
) {
1830 auto param
= method
.fd
->getParamDecl(i
);
1832 if (generator::is_callback(param
->getType()))
1834 os
<< param
->getName().str();
1841 /* Print a definition of the member or static method "method"
1842 * with signature "sig".
1844 * The body calls the corresponding method of the base class
1845 * in the plain interface and
1846 * then casts the result to the templated result type.
1848 void template_cpp_generator::method_impl_printer::print_method_body(
1849 const Method
&method
, const Signature
&sig
)
1851 const auto &base_name
= instance
.base_name();
1854 os
<< " auto res = ";
1855 os
<< base_name
<< "::" << method
.name
;
1856 method
.print_cpp_arg_list(os
, [&] (int i
, int arg
) {
1857 os
<< method
.fd
->getParamDecl(i
)->getName().str();
1862 print_return_type(method
, sig
.ret
);
1867 /* Print a definition of the method "method" with signature "sig",
1868 * if "deleted" is not set.
1870 * If "deleted" is set, then the corresponding declaration
1871 * is marked "delete" and no definition needs to be printed.
1873 * Otherwise print the method header, preceded by the template parameters,
1875 * The body depends on whether the method is a constructor or
1876 * takes any callbacks.
1878 void template_cpp_generator::method_impl_printer::print_method_sig(
1879 const Method
&method
, const Signature
&sig
, bool deleted
)
1885 print_non_empty_template(os
, instance
.kind
.params());
1886 print_method_header(method
, sig
);
1888 if (method
.kind
== Method::Kind::constructor
)
1889 print_constructor_body(method
, sig
);
1890 else if (method
.callbacks
.size() != 0)
1891 print_callback_method_body(method
, sig
);
1893 print_method_body(method
, sig
);
1896 /* Print a definition for the "get" method "fd" in class "clazz",
1897 * using a name that includes the "get_" prefix, to "os".
1899 * The declarations of these methods are explicitly delete'd
1900 * so no definition needs to be printed.
1902 void template_cpp_generator::method_impl_printer::print_get_method(
1907 /* Print a declaration or definition of the static method "method",
1908 * if it has a signature specified by static_methods.
1910 void template_cpp_generator::class_printer::print_static_method(
1911 const Method
&method
)
1913 print_special_method(method
, static_methods
);
1916 /* Signatures for constructors from a string.
1918 static Signature params_from_str
= { { }, { { Ctx
}, { Str
} } };
1919 static Signature set_from_str
= { { Domain
}, { { Ctx
}, { Str
} } };
1920 static Signature map_from_str
= { { Domain
, Range
}, { { Ctx
}, { Str
} } };
1921 static std::vector
<Signature
> from_str
=
1922 { params_from_str
, set_from_str
, map_from_str
};
1924 /* Signature for a constructor from an integer.
1926 static Signature int_from_si
= { { Anonymous
}, { { Ctx
}, { Integer
} } };
1928 /* Signatures for constructors of lists from the initial number
1931 static Signature alloc_params
= { { }, { { Ctx
}, { Integer
} } };
1932 static Signature alloc_set
= { { Domain
}, { { Ctx
}, { Integer
} } };
1933 static Signature alloc_map
= { { Domain
, Range
}, { { Ctx
}, { Integer
} } };
1935 /* Signatures for constructors and methods named after some other class.
1937 * Two forms of constructors are handled
1938 * - conversion from another object
1939 * - construction of a multi-expression from a space and a list
1941 * Methods named after some other class also come in two forms
1942 * - extraction of information such as the space or a list
1943 * - construction of a multi-expression from a space and a list
1945 * In both cases, the first form is a unary operation and
1946 * the second has an extra argument with a kind that is equal
1947 * to that of the first argument, except that the final tuple is anonymous.
1949 static std::vector
<Signature
> constructor_sig
= {
1957 /* Signatures for constructors derived from methods
1958 * with the given names that override the default signatures.
1960 static const std::unordered_map
<std::string
, std::vector
<Signature
>>
1961 special_constructors
{
1962 { "alloc", { alloc_params
, alloc_set
, alloc_map
} },
1963 { "int_from_si", { int_from_si
} },
1964 { "read_from_str", from_str
},
1967 /* Print a declaration or definition of the constructor "method".
1969 void template_cpp_generator::class_printer::print_constructor(
1970 const Method
&method
)
1972 if (special_constructors
.count(method
.name
) != 0) {
1973 const auto &sigs
= special_constructors
.at(method
.name
);
1974 return print_matching_method(method
, sigs
);
1976 print_matching_method(method
, constructor_sig
);
1979 /* Does this template class represent an anonymous function?
1981 * If any specialization represents an anonymous function,
1982 * then every specialization does, so simply check
1983 * the first specialization.
1985 bool template_class::is_anon() const
1987 return class_tuples
[0].is_anon();
1990 /* Does this template class represent an anonymous value?
1992 * That is, is there only a single specialization that moreover
1993 * has a single, anonymous tuple?
1995 bool template_class::is_anon_set() const
1997 return class_tuples
.size() == 1 && class_tuples
[0].is_anon_set();
2000 /* Update the substitution "sub" to map "general" to "specific"
2001 * if "specific" is a special case of "general" consistent with "sub",
2002 * given that "general" is not a pair and can be assigned "specific".
2003 * Return true if successful.
2004 * Otherwise, return false.
2006 * Check whether "general" is already assigned something in "sub".
2007 * If so, it must be assigned "specific".
2008 * Otherwise, there is a conflict.
2010 static bool update_sub_base(Substitution
&sub
, const TupleKindPtr
&general
,
2011 const TupleKindPtr
&specific
)
2013 auto name
= general
->name
;
2015 if (sub
.count(name
) != 0 && sub
.at(name
) != specific
)
2017 sub
.emplace(name
, specific
);
2021 /* Update the substitution "sub" to map "general" to "specific"
2022 * if "specific" is a special case of "general" consistent with "sub".
2023 * Return true if successful.
2024 * Otherwise, return false.
2026 * If "general" is a pair and "specific" is not,
2027 * then "specific" cannot be a special case.
2028 * If both are pairs, then update the substitution based
2030 * If "general" is Anonymous, then "specific" must be Anonymous as well.
2031 * If "general" is Leaf, then "specific" cannot be a pair.
2033 * Otherwise, assign "specific" to "general", if possible.
2035 static bool update_sub(Substitution
&sub
, const TupleKindPtr
&general
,
2036 const TupleKindPtr
&specific
)
2038 if (general
->left() && !specific
->left())
2040 if (general
->left())
2041 return update_sub(sub
, general
->left(), specific
->left()) &&
2042 update_sub(sub
, general
->right(), specific
->right());
2043 if (general
== Anonymous
&& specific
!= Anonymous
)
2045 if (general
== Leaf
&& specific
->left())
2048 return update_sub_base(sub
, general
, specific
);
2051 /* Check if "specific" is a special case of "general" and,
2052 * if so, return true along with a substitution
2053 * that maps "general" to "specific".
2054 * Otherwise return false.
2056 * This can only happen if the number of tuple kinds is the same.
2057 * If so, start with an empty substitution and update it
2058 * for each pair of tuple kinds, checking that each update succeeds.
2060 static std::pair
<bool, Substitution
> specializer(const Kind
&general
,
2061 const Kind
&specific
)
2063 Substitution specializer
;
2065 if (general
.size() != specific
.size())
2066 return { false, Substitution() };
2068 for (size_t i
= 0; i
< general
.size(); ++i
) {
2069 auto general_tuple
= general
[i
];
2071 if (!update_sub(specializer
, general
[i
], specific
[i
]))
2072 return { false, Substitution() };
2075 return { true, specializer
};
2078 /* Is "kind1" equivalent to "kind2"?
2079 * That is, is each a special case of the other?
2081 static bool equivalent(const Kind
&kind1
, const Kind
&kind2
)
2083 return specializer(kind1
, kind2
).first
&&
2084 specializer(kind2
, kind1
).first
;
2087 /* Add the specialization "kind" to the sequence of specializations,
2088 * provided there is no equivalent specialization already in there.
2090 void template_class::add_specialization(const Kind
&kind
)
2092 for (const auto &special
: class_tuples
)
2093 if (equivalent(special
, kind
))
2095 class_tuples
.emplace_back(kind
);
2098 /* A type printer that prints the plain interface type,
2099 * without namespace.
2101 struct plain_cpp_type_printer
: public cpp_type_printer
{
2102 plain_cpp_type_printer() {}
2104 virtual std::string
qualified(int arg
, const std::string
&cpp_type
)
2108 /* Return the qualified form of the given C++ isl type name appearing
2109 * in argument position "arg" (-1 for return type).
2111 * For printing the plain type without namespace, no modifications
2114 std::string
plain_cpp_type_printer::qualified(int arg
,
2115 const std::string
&cpp_type
) const
2120 /* Return a string representation of the plain type "type".
2122 * For the plain printer, the argument position is irrelevant,
2123 * so simply pass in -1.
2125 static std::string
plain_type(QualType type
)
2127 return plain_cpp_type_printer().param(-1, type
);
2130 /* Return a string representation of the plain return type of "method".
2132 static std::string
plain_return_type(const Method
&method
)
2134 return plain_type(method
.fd
->getReturnType());
2137 /* Return that part of the signature "sig" that should match
2138 * the template class specialization for the given method.
2140 * In particular, if the method is a regular member method,
2141 * then the instance should match the first argument.
2142 * Otherwise, it should match the return kind.
2144 static const Kind
&matching_kind(const Method
&method
, const Signature
&sig
)
2146 if (method
.kind
== Method::Kind::member_method
)
2152 /* Is it possible for "template_class" to have the given kind?
2154 * If the template class represents an anonymous function,
2155 * then so must the given kind.
2156 * There should also be specialization with the same number of tuple kinds.
2158 static bool has_kind(const template_class
&template_class
, const Kind
&kind
)
2160 if (template_class
.is_anon() && !kind
.is_anon())
2162 for (const auto &class_tuple
: template_class
.class_tuples
)
2163 if (class_tuple
.size() == kind
.size())
2168 /* Is "return_kind" a possible kind for the return type of "method"?
2170 * If the return type is not a template class,
2171 * then "return_kind" should not have any template parameters.
2172 * Otherwise, "return_kind" should be a valid kind for the template class.
2174 bool template_cpp_generator::class_printer::is_return_kind(
2175 const Method
&method
, const Kind
&return_kind
)
2177 const auto &template_classes
= generator
.template_classes
;
2178 auto return_type
= plain_return_type(method
);
2180 if (template_classes
.count(return_type
) == 0)
2181 return return_kind
.params().size() == 0;
2182 return has_kind(template_classes
.at(return_type
), return_kind
);
2185 /* Is "kind" a placeholder that can be assigned something else
2186 * in a substitution?
2188 * Anonymous can only be mapped to itself. This is taken care of
2190 * Leaf can only be assigned a placeholder, but there is no need
2191 * to handle this specifically since Leaf can still be assigned
2192 * to the placeholder.
2194 static bool assignable(const TupleKindPtr
&kind
)
2196 return kind
!= Anonymous
&& kind
!= Leaf
;
2199 /* Return a substitution that maps "kind1" to "kind2", if possible.
2200 * Otherwise return an empty substitution.
2202 * Check if "kind1" can be assigned anything or
2203 * if "kind1" and "kind2" are identical.
2204 * The latter case handles mapping Anonymous to itself.
2206 static Substitution
assign(const TupleKindPtr
&kind1
, const TupleKindPtr
&kind2
)
2210 if (assignable(kind1
) || kind1
== kind2
)
2211 res
.emplace(kind1
->name
, kind2
);
2215 /* Return a substitution that first applies "first" and then "second".
2217 * The result consists of "second" and of "second" applied to "first".
2219 static Substitution
compose(const Substitution
&first
,
2220 const Substitution
&second
)
2222 Substitution res
= second
;
2224 for (const auto &kvp
: first
)
2225 res
.emplace(kvp
.first
, apply(kvp
.second
, second
));
2230 static Substitution
compute_unifier(const TupleKindPtr
&kind1
,
2231 const TupleKindPtr
&kind2
);
2233 /* Try and extend "unifier" with a unifier for "kind1" and "kind2".
2234 * Return the resulting unifier if successful.
2235 * Otherwise, return an empty substitution.
2237 * First apply "unifier" to "kind1" and "kind2".
2238 * Then compute a unifier for the resulting tuple kinds and
2239 * combine it with "unifier".
2241 static Substitution
combine_unifiers(const TupleKindPtr
&kind1
,
2242 const TupleKindPtr
&kind2
, const Substitution
&unifier
)
2244 auto k1
= apply(kind1
, unifier
);
2245 auto k2
= apply(kind2
, unifier
);
2246 auto u
= compute_unifier(k1
, k2
);
2248 return Substitution();
2249 return compose(unifier
, u
);
2252 /* Try and compute a unifier of "kind1" and "kind2",
2253 * i.e., a substitution that produces the same result when
2254 * applied to both "kind1" and "kind2",
2255 * for the case where both "kind1" and "kind2" are pairs.
2256 * Return this unifier if it was found.
2257 * Return an empty substitution if no unifier can be found.
2259 * First compute a unifier for the left parts of the pairs and,
2260 * if successful, combine it with a unifier for the right parts.
2262 static Substitution
compute_pair_unifier(const TupleKindPtr
&kind1
,
2263 const TupleKindPtr
&kind2
)
2265 auto unifier_left
= compute_unifier(kind1
->left(), kind2
->left());
2266 if (unifier_left
.size() == 0)
2267 return Substitution();
2268 return combine_unifiers(kind1
->right(), kind2
->right(), unifier_left
);
2271 /* Try and compute a unifier of "kind1" and "kind2",
2272 * i.e., a substitution that produces the same result when
2273 * applied to both "kind1" and "kind2".
2274 * Return this unifier if it was found.
2275 * Return an empty substitution if no unifier can be found.
2277 * If one of the tuple kinds is a pair then assign it
2278 * to the other tuple kind, if possible.
2279 * If neither is a pair, then try and assign one to the other.
2280 * Otherwise, let compute_pair_unifier compute a unifier.
2282 * Note that an assignment is added to the unifier even
2283 * if "kind1" and "kind2" are identical.
2284 * This ensures that a successful substitution is never empty.
2286 static Substitution
compute_unifier(const TupleKindPtr
&kind1
,
2287 const TupleKindPtr
&kind2
)
2289 if (kind1
->left() && !kind2
->left())
2290 return assign(kind2
, kind1
);
2291 if (!kind1
->left() && kind2
->left())
2292 return assign(kind1
, kind2
);
2293 if (!kind1
->left() && !kind2
->left()) {
2294 if (assignable(kind1
))
2295 return assign(kind1
, kind2
);
2297 return assign(kind2
, kind1
);
2300 return compute_pair_unifier(kind1
, kind2
);
2303 /* Try and compute a unifier of "kind1" and "kind2",
2304 * i.e., a substitution that produces the same result when
2305 * applied to both "kind1" and "kind2".
2306 * Return this unifier if it was found.
2307 * Return an empty substitution if no unifier can be found.
2309 * Start with an empty substitution and compute a unifier for
2310 * each pair of tuple kinds, combining the results.
2311 * If no combined unifier can be found or
2312 * if the numbers of tuple kinds are different, then return
2313 * an empty substitution.
2314 * This assumes that the number of tuples is greater than zero,
2315 * as otherwise an empty substitution would be returned as well.
2317 static Substitution
compute_unifier(const Kind
&kind1
, const Kind
&kind2
)
2319 Substitution unifier
;
2321 if (kind1
.size() != kind2
.size())
2322 return Substitution();
2324 for (size_t i
= 0; i
< kind1
.size(); ++i
)
2325 unifier
= combine_unifiers(kind1
[i
], kind2
[i
], unifier
);
2330 /* Try and construct a Kind that is a specialization of both "general" and
2331 * "specific", where "specific" is known _not_ to be a specialization
2332 * of "general" and not to contain any Leaf.
2334 * First check whether "general" is a specialization of "specific".
2335 * If so, simply return "general".
2336 * Otherwise, rename the placeholders in the two kinds apart and
2337 * try and compute a unifier.
2338 * If this succeeds, then return the result of applying the unifier.
2340 static std::pair
<bool, Kind
> unify(const Kind
&general
, const Kind
&specific
)
2342 if (specializer(specific
, general
).first
) {
2343 return { true, general
};
2345 auto rename
= param_renamer(specific
.params(), "T");
2346 auto renamed
= specific
.apply(rename
);
2347 auto unifier
= compute_unifier(general
, renamed
);
2349 if (unifier
.size() == 0)
2350 return { false, { } };
2352 return { true, general
.apply(unifier
) };
2356 /* Try and add a template class specialization corresponding to "kind".
2357 * The new specialization needs to be a specialization of both
2358 * the current specialization and "kind".
2360 * The current template class specialization is known not to be a special case
2363 * Try and unify the two kinds and, if this succeeds, add the result
2364 * to this list of template class specializations.
2366 void template_cpp_generator::class_printer::add_specialization(
2369 auto maybe_unified
= unify(kind
, instance
.kind
);
2371 if (!maybe_unified
.first
)
2373 instance
.template_class
.add_specialization(maybe_unified
.second
);
2376 /* Does the type of the parameter at position "i" of "method" necessarily
2377 * have a final Anonymous tuple?
2379 * If the parameter is not of an isl type or if no specializations
2380 * have been defined for the type, then it can be considered anonymous.
2381 * Otherwise, if any specialization represents an anonymous function,
2382 * then every specialization does, so simply check
2383 * the first specialization.
2385 static bool param_is_anon(const Method
&method
, int i
)
2387 ParmVarDecl
*param
= method
.get_param(i
);
2388 QualType type
= param
->getOriginalType();
2390 if (cpp_generator::is_isl_type(type
)) {
2391 const auto &name
= type
->getPointeeType().getAsString();
2392 const auto &cpp
= cpp_generator::type2cpp(name
);
2393 const auto &tuples
= lookup_class_tuples(cpp
);
2397 return tuples
[0].is_anon();
2403 /* Replace the final tuple of "arg_kind" by Anonymous in "sig" and
2404 * return the update signature,
2405 * unless this would affect the class instance "instance_kind".
2407 * If the original "instance_kind" is a special case
2408 * of the result of the substitution, then "instance_kind"
2409 * is not affected and the substitution can be applied
2410 * to the entire signature.
2412 static Signature
specialize_anonymous_arg(const Signature
&sig
,
2413 const Kind
&arg_kind
, const Kind
&instance_kind
)
2415 const auto &subs
= compute_unifier(arg_kind
.back(), Anonymous
);
2416 const auto &specialized_instance
= instance_kind
.apply(subs
);
2418 if (!specializer(specialized_instance
, instance_kind
).first
)
2421 return sig
.apply(subs
);
2424 /* If any of the arguments of "method" is of a type that necessarily
2425 * has a final Anonymous tuple, but the corresponding entry
2426 * in the signature "sig" is not Anonymous, then replace
2427 * that entry by Anonymous and return the updated signature,
2428 * unless this would affect the class instance "instance_kind".
2430 static Signature
specialize_anonymous_args(const Signature
&sig
,
2431 const Method
&method
, const Kind
&instance_kind
)
2433 auto specialized_sig
= sig
;
2435 method
.on_cpp_arg_list([&] (int i
, int arg
) {
2436 const auto &arg_kind
= sig
.args
[arg
];
2438 if (arg_kind
.is_anon())
2440 if (!param_is_anon(method
, i
))
2442 specialized_sig
= specialize_anonymous_arg(specialized_sig
,
2443 arg_kind
, instance_kind
);
2446 return specialized_sig
;
2449 /* Print a declaration or definition of the method "method"
2450 * if the template class specialization matches "match_arg".
2451 * Return true if so.
2452 * "sig" is the complete signature, of which "match_arg" refers
2453 * to the first argument or the return type.
2455 * Since "sig" may have parameters with the same names as
2456 * those in instance.kind, rename them apart first.
2458 * If the template class specialization is a special case of
2459 * (the renamed) "match_arg"
2460 * then apply the specializer to the complete (renamed) signature,
2461 * specialize any anonymous arguments,
2462 * check that the return kind is allowed and, if so,
2463 * print the declaration or definition using the specialized signature.
2465 * If the template class specialization is not a special case of "match_arg"
2466 * then add a further specialization to the list of specializations
2467 * of the template class.
2469 bool template_cpp_generator::class_printer::print_matching_method(
2470 const Method
&method
, const Signature
&sig
, const Kind
&match_arg
)
2472 auto rename
= shared_param_renamer(sig
, instance
.kind
);
2473 auto renamed_arg
= match_arg
.apply(rename
);
2474 auto maybe_specializer
= specializer(renamed_arg
, instance
.kind
);
2475 if (maybe_specializer
.first
) {
2476 const auto &specializer
= maybe_specializer
.second
;
2477 auto specialized_sig
= sig
.apply(rename
).apply(specializer
);
2478 specialized_sig
= specialize_anonymous_args(specialized_sig
,
2479 method
, instance
.kind
);
2480 if (!is_return_kind(method
, specialized_sig
.ret
))
2483 print_method_sig(method
, specialized_sig
, false);
2485 add_specialization(match_arg
);
2487 return maybe_specializer
.first
;
2490 /* Is the first argument of "method" of type "isl_ctx *"?
2492 static bool first_arg_is_ctx(const Method
&method
)
2494 return generator::first_arg_is_isl_ctx(method
.fd
);
2497 /* Is the first signature argument set to { Ctx }?
2499 static bool first_kind_is_ctx(const Signature
&sig
)
2501 return sig
.args
[0].size() > 0 && sig
.args
[0][0] == Ctx
;
2504 /* Print a declaration or definition of the member method "method"
2505 * if it matches the signature "sig".
2506 * Return true if so.
2508 * First determine the part of the signature that needs to match
2509 * the template class specialization and
2510 * check that it has the same number of template arguments.
2511 * Also check that the number of arguments of the signature
2512 * matches that of the method.
2513 * If there is at least one argument, then check that the first method argument
2514 * is an isl_ctx if and only if the first signature argument is Ctx.
2516 * If these tests succeed, proceed with the actual matching.
2518 bool template_cpp_generator::class_printer::print_matching_method(
2519 const Method
&method
, const Signature
&sig
)
2521 auto match_arg
= matching_kind(method
, sig
);
2522 int n_args
= sig
.args
.size();
2524 if (match_arg
.size() != instance
.kind
.size())
2526 if (n_args
!= total_params(method
))
2528 if (n_args
> 0 && first_arg_is_ctx(method
) != first_kind_is_ctx(sig
))
2531 return print_matching_method(method
, sig
, match_arg
);
2534 /* Print a declaration or definition of the member method "method"
2535 * for each matching signature in "signatures".
2537 * If there is no matching signature in "signatures",
2538 * then explicitly delete the method (using a signature based on
2539 * the specialization) so that it is not inherited from the base class.
2541 void template_cpp_generator::class_printer::print_matching_method(
2542 const Method
&method
, const std::vector
<Signature
> &signatures
)
2546 for (const auto &sig
: signatures
)
2547 if (print_matching_method(method
, sig
))
2551 print_method_sig(method
, instance_sig(method
, instance
), true);
2554 /* Signatures for "at" methods applied to a multi-expression,
2555 * which make the final tuple anonymous.
2557 static Signature select_set
= { { Anonymous
}, { { Domain
}, { Integer
} } };
2558 static Signature select_map
=
2559 { { Domain
, Anonymous
}, { { Domain
, Range
}, { Integer
} } };
2560 static std::vector
<Signature
> at_select
= { select_set
, select_map
};
2562 /* Signatures for other "at" methods applied to a list,
2563 * which do not modify the tuple kind.
2565 static Signature bin_set_int
= { { Domain
}, { { Domain
}, { Integer
} } };
2566 static Signature bin_map_int
=
2567 { { Domain
, Range
}, { { Domain
, Range
}, { Integer
} } };
2568 static std::vector
<Signature
> at_keep
= { bin_set_int
, bin_map_int
};
2570 /* Print a declaration or definition of the "at" member method "method".
2572 * There are two types of methods called "at".
2573 * One type extracts an element from a multi-expression and
2574 * the other extracts an element from a list.
2576 * In the first case, the return type is an anonymous function
2577 * while the object type is not. In this case, the return kind
2578 * should have a final Anonymous tuple.
2579 * Otherwise, the return kind should be the same as the object kind.
2581 void template_cpp_generator::class_printer::print_at_method(
2582 const Method
&method
)
2584 auto anon
= instance
.template_class
.is_anon();
2585 auto return_type
= plain_return_type(method
);
2586 auto return_class
= generator
.template_classes
.at(return_type
);
2588 if (!anon
&& return_class
.is_anon())
2589 return print_matching_method(method
, at_select
);
2591 return print_matching_method(method
, at_keep
);
2594 /* Does the string "s" contain "sub" as a substring?
2596 static bool contains(const std::string
&s
, const std::string
&sub
)
2598 return s
.find(sub
) != std::string::npos
;
2601 /* Print a declaration or definition of the member method "method",
2602 * if it has a special signature in "special_methods".
2603 * Return true if this is the case.
2605 * Check if any special signatures are specified for this method and
2606 * if the class name matches any of those with special signatures.
2607 * If so, pick the one with the best match, i.e., the first match
2608 * since the largest keys appear first.
2610 bool template_cpp_generator::class_printer::print_special_method(
2611 const Method
&method
, const infix_map_map
&special_methods
)
2613 if (special_methods
.count(method
.name
) == 0)
2616 for (const auto &kvp
: special_methods
.at(method
.name
)) {
2617 if (!contains(instance
.template_class
.class_name
, kvp
.first
))
2619 print_matching_method(method
, kvp
.second
);
2626 /* Print a declaration or definition of the member method "method",
2627 * if it has a special signature specified by special_member_methods.
2628 * Return true if this is the case.
2630 bool template_cpp_generator::class_printer::print_special_member_method(
2631 const Method
&method
)
2633 return print_special_method(method
, special_member_methods
);
2636 /* Print a declaration or definition of the member method "method",
2637 * if it is named after a template class. Return true if this is the case.
2639 bool template_cpp_generator::class_printer::print_type_named_member_method(
2640 const Method
&method
)
2642 if (generator
.template_classes
.count(method
.name
) == 0)
2645 print_matching_method(method
, constructor_sig
);
2650 /* Print a declaration or definition of the member method "method"
2651 * using a signature associated to method name "name", if there is any.
2652 * Return true if this is the case.
2654 bool template_cpp_generator::class_printer::print_member_method_with_name(
2655 const Method
&method
, const std::string
&name
)
2657 if (member_methods
.count(name
) == 0)
2660 print_matching_method(method
, member_methods
.at(name
));
2664 /* If "sub" appears inside "str", then remove the first occurrence and
2665 * return the result. Otherwise, simply return "str".
2667 static std::string
drop_occurrence(const std::string
&str
,
2668 const std::string
&sub
)
2671 auto pos
= str
.find(sub
);
2673 if (pos
!= std::string::npos
)
2674 res
.erase(pos
, sub
.length());
2679 /* If "sub" appears in "str" next to an underscore, then remove the combination.
2680 * Otherwise, simply return "str".
2682 static std::string
drop_underscore_occurrence(const std::string
&str
,
2683 const std::string
&sub
)
2685 auto res
= drop_occurrence(str
, sub
+ "_");
2688 return drop_occurrence(res
, std::string("_") + sub
);
2691 /* Return the name of "method", with the name of the return type,
2692 * along with an underscore, removed, if this combination appears in the name.
2693 * Otherwise, simply return the name.
2695 const std::string
name_without_return(const Method
&method
)
2697 auto return_infix
= plain_return_type(method
);
2698 return drop_underscore_occurrence(method
.name
, return_infix
);
2701 /* If this method has a callback, then remove the type
2702 * of the first argument of the first callback from the name of the method.
2703 * Otherwise, simply return the name of the method.
2705 const std::string
callback_name(const Method
&method
)
2707 if (method
.callbacks
.size() == 0)
2710 auto type
= method
.callbacks
.at(0)->getType();
2711 auto callback
= cpp_generator::extract_prototype(type
);
2712 auto arg_type
= plain_type(callback
->getArgType(0));
2713 return generator::drop_suffix(method
.name
, "_" + arg_type
);
2716 /* Print a declaration or definition of the member method "method".
2718 * If the method is called "at", then it requires special treatment.
2719 * Otherwise, check if the signature is overridden for this class or
2720 * if the method is named after some other type.
2721 * Otherwise look for an appropriate signature using different variations
2722 * of the method name. First try the method name itself,
2723 * then the method name with the return type removed and
2724 * finally the method name with the callback argument type removed.
2726 void template_cpp_generator::class_printer::print_member_method(
2727 const Method
&method
)
2729 if (method
.name
== "at")
2730 return print_at_method(method
);
2731 if (print_special_member_method(method
))
2733 if (print_type_named_member_method(method
))
2735 if (print_member_method_with_name(method
, method
.name
))
2737 if (print_member_method_with_name(method
, name_without_return(method
)))
2739 if (print_member_method_with_name(method
, callback_name(method
)))
2743 /* Print a declaration or definition of "method" based on its type.
2745 void template_cpp_generator::class_printer::print_any_method(
2746 const Method
&method
)
2748 switch (method
.kind
) {
2749 case Method::Kind::static_method
:
2750 print_static_method(method
);
2752 case Method::Kind::constructor
:
2753 print_constructor(method
);
2755 case Method::Kind::member_method
:
2756 print_member_method(method
);
2761 /* Print a declaration or definition of "method".
2763 * Mark the method as not requiring copies of the arguments.
2765 void template_cpp_generator::class_printer::print_method(const Method
&method
)
2767 print_any_method(NoCopyMethod(method
));
2770 /* Print a declaration or definition of "method".
2772 * Note that a ConversionMethod is already marked
2773 * as not requiring copies of the arguments.
2775 void template_cpp_generator::class_printer::print_method(
2776 const ConversionMethod
&method
)
2778 print_any_method(method
);
2781 /* Helper class for printing the declarations for
2782 * template class specializations.
2784 struct template_cpp_generator::class_decl_printer
:
2785 public specialization_printer
2787 class_decl_printer(std::ostream
&os
,
2788 template_cpp_generator
&generator
) :
2789 specialization_printer(os
, generator
) {}
2791 void print_arg_subclass_constructor(const specialization
&instance
,
2792 const std::vector
<std::string
> ¶ms
) const;
2793 void print_super_constructor(const specialization
&instance
) const;
2794 virtual void print_class(const specialization
&instance
) const override
;
2797 /* Print the declaration and definition of a constructor
2798 * for the template class specialization "instance" taking
2799 * an instance with more specialized template arguments,
2800 * where "params" holds the template parameters of "instance".
2801 * It is assumed that there is at least one template parameter as otherwise
2802 * there are no template arguments to be specialized and
2803 * no constructor needs to be printed.
2805 * In particular, the constructor takes an object of the same instance where
2806 * for each template parameter, the corresponding template argument
2807 * of the input object is a subclass of the template argument
2808 * of the constructed object.
2810 * Pick fresh names for all template parameters and
2811 * add a constructor with these fresh names as extra template parameters and
2812 * a constraint requiring that each of them is a subclass
2813 * of the corresponding class template parameter.
2814 * The plain C++ interface object of the constructed object is initialized with
2815 * the plain C++ interface object of the constructor argument.
2817 void template_cpp_generator::class_decl_printer::print_arg_subclass_constructor(
2818 const specialization
&instance
,
2819 const std::vector
<std::string
> ¶ms
) const
2821 const auto &class_name
= instance
.class_name();
2822 auto rename
= param_renamer(params
, "Arg");
2823 auto derived
= instance
.kind
.apply(rename
);
2827 print_pure_template_args(os
, derived
.params());
2829 os
<< " typename std::enable_if<\n";
2830 for (size_t i
= 0; i
< params
.size(); ++i
) {
2833 os
<< " std::is_base_of<"
2834 << params
[i
] << ", "
2835 << rename
.at(params
[i
])->params()[0] << ">{}";
2838 os
<< " bool>::type = true>";
2840 os
<< " " << class_name
<< "(const ";
2841 print_bare_template_type(os
, class_name
, derived
);
2842 os
<< " &obj) : " << instance
.base_name() << "(obj) {}\n";
2845 /* Print the declaration and definition of a constructor
2846 * for the template class specialization "instance" taking
2847 * an instance of the base class.
2849 * If the instance kind is that of an anonymous set
2850 * (i.e., it has a single tuple that is set to Anonymous),
2851 * then allow the constructor to be called externally.
2852 * This is mostly useful for being able to use isl::val and
2853 * isl::typed::val<Anonymous> interchangeably and similarly for isl::id.
2855 * If the instance is of any other kind, then make this constructor private
2856 * to avoid objects of the plain interface being converted automatically.
2857 * Also make sure that it does not apply to any type derived
2858 * from the base class. In particular, this makes sure it does
2859 * not apply to any other specializations of this template class as
2860 * otherwise any conflict in specializations would simply point
2861 * to the private constructor.
2863 * A factory method is added to be able to perform the conversion explicitly,
2864 * with an explicit specification of the template arguments.
2866 void template_cpp_generator::class_decl_printer::print_super_constructor(
2867 const specialization
&instance
) const
2869 bool hide
= !instance
.kind
.is_anon_set();
2870 const auto &base_name
= instance
.base_name();
2871 const auto &arg_name
= hide
? "base" : base_name
;
2874 os
<< " private:\n";
2875 os
<< " template <typename base,\n";
2876 os
<< " typename std::enable_if<\n";
2877 os
<< " std::is_same<base, " << base_name
2878 << ">{}, bool>::type = true>\n";
2880 os
<< " " << instance
.class_name()
2881 << "(const " << arg_name
<< " &obj) : "
2882 << base_name
<< "(obj) {}\n";
2885 os
<< " static " << instance
.class_name() << " from"
2886 << "(const " << base_name
<< " &obj) {\n";
2887 os
<< " return " << instance
.class_name() << "(obj);\n";
2891 /* Print a "declaration" for the given template class specialization.
2892 * In particular, print the class definition and the method declarations.
2894 * The template parameters are the distinct variable names
2895 * in the instance kind.
2897 * Each instance of the template class derives from the corresponding
2898 * plain C++ interface class.
2900 * All (other) template classes are made friends of this template class
2901 * to allow them to call the private constructor taking an object
2902 * of the plain interface.
2904 * Besides the constructors and methods that forward
2905 * to the corresponding methods in the plain C++ interface class,
2906 * some extra constructors are defined.
2907 * The default zero-argument constructor is useful for declaring
2908 * a variable that only gets assigned a value at a later stage.
2909 * The constructor taking an instance with more specialized
2910 * template arguments is useful for lifting the class hierarchy
2911 * of the template arguments to the template class.
2912 * The constructor taking an instance of the base class
2913 * is useful for (explicitly) constructing a template type
2914 * from a plain type.
2916 void template_cpp_generator::class_decl_printer::print_class(
2917 const specialization
&instance
) const
2919 const auto &class_name
= instance
.class_name();
2920 auto params
= instance
.kind
.params();
2924 print_template(os
, params
);
2927 print_bare_template_type(os
, class_name
, instance
.kind
);
2928 os
<< " : public " << instance
.base_name() << " {\n";
2930 generator
.print_friends(os
);
2933 os
<< " " << class_name
<< "() = default;\n";
2934 if (params
.size() != 0)
2935 print_arg_subclass_constructor(instance
, params
);
2936 print_super_constructor(instance
);
2937 method_decl_printer(instance
, *this).print_all_methods();
2942 /* Helper class for printing the definitions of template class specializations.
2944 struct template_cpp_generator::class_impl_printer
:
2945 public specialization_printer
2947 class_impl_printer(std::ostream
&os
,
2948 template_cpp_generator
&generator
) :
2949 specialization_printer(os
, generator
) {}
2951 virtual void print_class(const specialization
&instance
) const override
;
2954 /* Print a definition for the given template class specialization.
2956 * In particular, print definitions
2957 * for the constructors and methods that forward
2958 * to the corresponding methods in the plain C++ interface class.
2959 * The extra constructors declared in the class definition
2960 * are defined inline.
2962 void template_cpp_generator::class_impl_printer::print_class(
2963 const specialization
&instance
) const
2965 method_impl_printer(instance
, *this).print_all_methods();
2968 /* Generate a templated cpp interface
2969 * based on the extracted types and functions.
2971 * First print forward declarations for all template classes,
2972 * then the declarations of the classes, and at the end all
2973 * method implementations.
2975 void template_cpp_generator::generate()
2977 ostream
&os
= std::cout
;
2981 print_forward_declarations(os
);
2982 class_decl_printer(os
, *this).print_classes();
2983 class_impl_printer(os
, *this).print_classes();