/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/polly/lib/Transform/ScheduleTreeTransform.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- polly/ScheduleTreeTransform.cpp --------------------------*- C++ -*-===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | // |
9 | | // Make changes to isl's schedule tree data structure. |
10 | | // |
11 | | //===----------------------------------------------------------------------===// |
12 | | |
13 | | #include "polly/ScheduleTreeTransform.h" |
14 | | #include "polly/Support/ISLTools.h" |
15 | | #include "llvm/ADT/ArrayRef.h" |
16 | | #include "llvm/ADT/SmallVector.h" |
17 | | |
18 | | using namespace polly; |
19 | | |
20 | | namespace { |
21 | | |
22 | | /// This class defines a simple visitor class that may be used for |
23 | | /// various schedule tree analysis purposes. |
24 | | template <typename Derived, typename RetTy = void, typename... Args> |
25 | | struct ScheduleTreeVisitor { |
26 | 1.92k | Derived &getDerived() { return *static_cast<Derived *>(this); } ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::ExtensionNodeRewriter, isl::noexceptions::schedule, isl::noexceptions::union_set const&, isl::noexceptions::union_map&>::getDerived() Line | Count | Source | 26 | 296 | Derived &getDerived() { return *static_cast<Derived *>(this); } |
ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::ApplyASTBuildOptions, isl::noexceptions::schedule_node>::getDerived() Line | Count | Source | 26 | 776 | Derived &getDerived() { return *static_cast<Derived *>(this); } |
ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::CollectASTBuildOptions, void>::getDerived() Line | Count | Source | 26 | 848 | Derived &getDerived() { return *static_cast<Derived *>(this); } |
|
27 | | const Derived &getDerived() const { |
28 | | return *static_cast<const Derived *>(this); |
29 | | } |
30 | | |
31 | 864 | RetTy visit(const isl::schedule_node &Node, Args... args) { |
32 | 864 | assert(!Node.is_null()); |
33 | 864 | switch (isl_schedule_node_get_type(Node.get())) { |
34 | 864 | case isl_schedule_node_domain: |
35 | 36 | assert(isl_schedule_node_n_children(Node.get()) == 1); |
36 | 36 | return getDerived().visitDomain(Node, std::forward<Args>(args)...); |
37 | 864 | case isl_schedule_node_band: |
38 | 168 | assert(isl_schedule_node_n_children(Node.get()) == 1); |
39 | 168 | return getDerived().visitBand(Node, std::forward<Args>(args)...); |
40 | 864 | case isl_schedule_node_sequence: |
41 | 84 | assert(isl_schedule_node_n_children(Node.get()) >= 2); |
42 | 84 | return getDerived().visitSequence(Node, std::forward<Args>(args)...); |
43 | 864 | case isl_schedule_node_set: |
44 | 0 | return getDerived().visitSet(Node, std::forward<Args>(args)...); |
45 | 864 | assert(isl_schedule_node_n_children(Node.get()) >= 2); |
46 | 120 | case isl_schedule_node_leaf: |
47 | 120 | assert(isl_schedule_node_n_children(Node.get()) == 0); |
48 | 120 | return getDerived().visitLeaf(Node, std::forward<Args>(args)...); |
49 | 240 | case isl_schedule_node_mark: |
50 | 240 | assert(isl_schedule_node_n_children(Node.get()) == 1); |
51 | 240 | return getDerived().visitMark(Node, std::forward<Args>(args)...); |
52 | 48 | case isl_schedule_node_extension: |
53 | 48 | assert(isl_schedule_node_n_children(Node.get()) == 1); |
54 | 48 | return getDerived().visitExtension(Node, std::forward<Args>(args)...); |
55 | 168 | case isl_schedule_node_filter: |
56 | 168 | assert(isl_schedule_node_n_children(Node.get()) == 1); |
57 | 168 | return getDerived().visitFilter(Node, std::forward<Args>(args)...); |
58 | 0 | default: |
59 | 0 | llvm_unreachable("unimplemented schedule node type"); |
60 | 864 | } |
61 | 864 | } ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::ExtensionNodeRewriter, isl::noexceptions::schedule, isl::noexceptions::union_set const&, isl::noexceptions::union_map&>::visit(isl::noexceptions::schedule_node const&, isl::noexceptions::union_set const&, isl::noexceptions::union_map&) Line | Count | Source | 31 | 296 | RetTy visit(const isl::schedule_node &Node, Args... args) { | 32 | 296 | assert(!Node.is_null()); | 33 | 296 | switch (isl_schedule_node_get_type(Node.get())) { | 34 | 296 | case isl_schedule_node_domain: | 35 | 12 | assert(isl_schedule_node_n_children(Node.get()) == 1); | 36 | 12 | return getDerived().visitDomain(Node, std::forward<Args>(args)...); | 37 | 296 | case isl_schedule_node_band: | 38 | 56 | assert(isl_schedule_node_n_children(Node.get()) == 1); | 39 | 56 | return getDerived().visitBand(Node, std::forward<Args>(args)...); | 40 | 296 | case isl_schedule_node_sequence: | 41 | 28 | assert(isl_schedule_node_n_children(Node.get()) >= 2); | 42 | 28 | return getDerived().visitSequence(Node, std::forward<Args>(args)...); | 43 | 296 | case isl_schedule_node_set: | 44 | 0 | return getDerived().visitSet(Node, std::forward<Args>(args)...); | 45 | 296 | assert(isl_schedule_node_n_children(Node.get()) >= 2); | 46 | 40 | case isl_schedule_node_leaf: | 47 | 40 | assert(isl_schedule_node_n_children(Node.get()) == 0); | 48 | 40 | return getDerived().visitLeaf(Node, std::forward<Args>(args)...); | 49 | 80 | case isl_schedule_node_mark: | 50 | 80 | assert(isl_schedule_node_n_children(Node.get()) == 1); | 51 | 80 | return getDerived().visitMark(Node, std::forward<Args>(args)...); | 52 | 24 | case isl_schedule_node_extension: | 53 | 24 | assert(isl_schedule_node_n_children(Node.get()) == 1); | 54 | 24 | return getDerived().visitExtension(Node, std::forward<Args>(args)...); | 55 | 56 | case isl_schedule_node_filter: | 56 | 56 | assert(isl_schedule_node_n_children(Node.get()) == 1); | 57 | 56 | return getDerived().visitFilter(Node, std::forward<Args>(args)...); | 58 | 0 | default: | 59 | 0 | llvm_unreachable("unimplemented schedule node type"); | 60 | 296 | } | 61 | 296 | } |
ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::ApplyASTBuildOptions, isl::noexceptions::schedule_node>::visit(isl::noexceptions::schedule_node const&) Line | Count | Source | 31 | 272 | RetTy visit(const isl::schedule_node &Node, Args... args) { | 32 | 272 | assert(!Node.is_null()); | 33 | 272 | switch (isl_schedule_node_get_type(Node.get())) { | 34 | 272 | case isl_schedule_node_domain: | 35 | 12 | assert(isl_schedule_node_n_children(Node.get()) == 1); | 36 | 12 | return getDerived().visitDomain(Node, std::forward<Args>(args)...); | 37 | 272 | case isl_schedule_node_band: | 38 | 56 | assert(isl_schedule_node_n_children(Node.get()) == 1); | 39 | 56 | return getDerived().visitBand(Node, std::forward<Args>(args)...); | 40 | 272 | case isl_schedule_node_sequence: | 41 | 28 | assert(isl_schedule_node_n_children(Node.get()) >= 2); | 42 | 28 | return getDerived().visitSequence(Node, std::forward<Args>(args)...); | 43 | 272 | case isl_schedule_node_set: | 44 | 0 | return getDerived().visitSet(Node, std::forward<Args>(args)...); | 45 | 272 | assert(isl_schedule_node_n_children(Node.get()) >= 2); | 46 | 40 | case isl_schedule_node_leaf: | 47 | 40 | assert(isl_schedule_node_n_children(Node.get()) == 0); | 48 | 40 | return getDerived().visitLeaf(Node, std::forward<Args>(args)...); | 49 | 80 | case isl_schedule_node_mark: | 50 | 80 | assert(isl_schedule_node_n_children(Node.get()) == 1); | 51 | 80 | return getDerived().visitMark(Node, std::forward<Args>(args)...); | 52 | 0 | case isl_schedule_node_extension: | 53 | 0 | assert(isl_schedule_node_n_children(Node.get()) == 1); | 54 | 0 | return getDerived().visitExtension(Node, std::forward<Args>(args)...); | 55 | 56 | case isl_schedule_node_filter: | 56 | 56 | assert(isl_schedule_node_n_children(Node.get()) == 1); | 57 | 56 | return getDerived().visitFilter(Node, std::forward<Args>(args)...); | 58 | 0 | default: | 59 | 0 | llvm_unreachable("unimplemented schedule node type"); | 60 | 272 | } | 61 | 272 | } |
ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::CollectASTBuildOptions, void>::visit(isl::noexceptions::schedule_node const&) Line | Count | Source | 31 | 296 | RetTy visit(const isl::schedule_node &Node, Args... args) { | 32 | 296 | assert(!Node.is_null()); | 33 | 296 | switch (isl_schedule_node_get_type(Node.get())) { | 34 | 296 | case isl_schedule_node_domain: | 35 | 12 | assert(isl_schedule_node_n_children(Node.get()) == 1); | 36 | 12 | return getDerived().visitDomain(Node, std::forward<Args>(args)...); | 37 | 296 | case isl_schedule_node_band: | 38 | 56 | assert(isl_schedule_node_n_children(Node.get()) == 1); | 39 | 56 | return getDerived().visitBand(Node, std::forward<Args>(args)...); | 40 | 296 | case isl_schedule_node_sequence: | 41 | 28 | assert(isl_schedule_node_n_children(Node.get()) >= 2); | 42 | 28 | return getDerived().visitSequence(Node, std::forward<Args>(args)...); | 43 | 296 | case isl_schedule_node_set: | 44 | 0 | return getDerived().visitSet(Node, std::forward<Args>(args)...); | 45 | 296 | assert(isl_schedule_node_n_children(Node.get()) >= 2); | 46 | 40 | case isl_schedule_node_leaf: | 47 | 40 | assert(isl_schedule_node_n_children(Node.get()) == 0); | 48 | 40 | return getDerived().visitLeaf(Node, std::forward<Args>(args)...); | 49 | 80 | case isl_schedule_node_mark: | 50 | 80 | assert(isl_schedule_node_n_children(Node.get()) == 1); | 51 | 80 | return getDerived().visitMark(Node, std::forward<Args>(args)...); | 52 | 24 | case isl_schedule_node_extension: | 53 | 24 | assert(isl_schedule_node_n_children(Node.get()) == 1); | 54 | 24 | return getDerived().visitExtension(Node, std::forward<Args>(args)...); | 55 | 56 | case isl_schedule_node_filter: | 56 | 56 | assert(isl_schedule_node_n_children(Node.get()) == 1); | 57 | 56 | return getDerived().visitFilter(Node, std::forward<Args>(args)...); | 58 | 0 | default: | 59 | 0 | llvm_unreachable("unimplemented schedule node type"); | 60 | 296 | } | 61 | 296 | } |
|
62 | | |
63 | 24 | RetTy visitDomain(const isl::schedule_node &Domain, Args... args) { |
64 | 24 | return getDerived().visitSingleChild(Domain, std::forward<Args>(args)...); |
65 | 24 | } ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::ApplyASTBuildOptions, isl::noexceptions::schedule_node>::visitDomain(isl::noexceptions::schedule_node const&) Line | Count | Source | 63 | 12 | RetTy visitDomain(const isl::schedule_node &Domain, Args... args) { | 64 | 12 | return getDerived().visitSingleChild(Domain, std::forward<Args>(args)...); | 65 | 12 | } |
ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::CollectASTBuildOptions, void>::visitDomain(isl::noexceptions::schedule_node const&) Line | Count | Source | 63 | 12 | RetTy visitDomain(const isl::schedule_node &Domain, Args... args) { | 64 | 12 | return getDerived().visitSingleChild(Domain, std::forward<Args>(args)...); | 65 | 12 | } |
|
66 | | |
67 | 112 | RetTy visitBand(const isl::schedule_node &Band, Args... args) { |
68 | 112 | return getDerived().visitSingleChild(Band, std::forward<Args>(args)...); |
69 | 112 | } ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::ApplyASTBuildOptions, isl::noexceptions::schedule_node>::visitBand(isl::noexceptions::schedule_node const&) Line | Count | Source | 67 | 56 | RetTy visitBand(const isl::schedule_node &Band, Args... args) { | 68 | 56 | return getDerived().visitSingleChild(Band, std::forward<Args>(args)...); | 69 | 56 | } |
ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::CollectASTBuildOptions, void>::visitBand(isl::noexceptions::schedule_node const&) Line | Count | Source | 67 | 56 | RetTy visitBand(const isl::schedule_node &Band, Args... args) { | 68 | 56 | return getDerived().visitSingleChild(Band, std::forward<Args>(args)...); | 69 | 56 | } |
|
70 | | |
71 | 56 | RetTy visitSequence(const isl::schedule_node &Sequence, Args... args) { |
72 | 56 | return getDerived().visitMultiChild(Sequence, std::forward<Args>(args)...); |
73 | 56 | } ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::ApplyASTBuildOptions, isl::noexceptions::schedule_node>::visitSequence(isl::noexceptions::schedule_node const&) Line | Count | Source | 71 | 28 | RetTy visitSequence(const isl::schedule_node &Sequence, Args... args) { | 72 | 28 | return getDerived().visitMultiChild(Sequence, std::forward<Args>(args)...); | 73 | 28 | } |
ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::CollectASTBuildOptions, void>::visitSequence(isl::noexceptions::schedule_node const&) Line | Count | Source | 71 | 28 | RetTy visitSequence(const isl::schedule_node &Sequence, Args... args) { | 72 | 28 | return getDerived().visitMultiChild(Sequence, std::forward<Args>(args)...); | 73 | 28 | } |
|
74 | | |
75 | 0 | RetTy visitSet(const isl::schedule_node &Set, Args... args) { |
76 | 0 | return getDerived().visitMultiChild(Set, std::forward<Args>(args)...); |
77 | 0 | } Unexecuted instantiation: ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::ApplyASTBuildOptions, isl::noexceptions::schedule_node>::visitSet(isl::noexceptions::schedule_node const&) Unexecuted instantiation: ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::CollectASTBuildOptions, void>::visitSet(isl::noexceptions::schedule_node const&) |
78 | | |
79 | 80 | RetTy visitLeaf(const isl::schedule_node &Leaf, Args... args) { |
80 | 80 | return getDerived().visitNode(Leaf, std::forward<Args>(args)...); |
81 | 80 | } ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::ApplyASTBuildOptions, isl::noexceptions::schedule_node>::visitLeaf(isl::noexceptions::schedule_node const&) Line | Count | Source | 79 | 40 | RetTy visitLeaf(const isl::schedule_node &Leaf, Args... args) { | 80 | 40 | return getDerived().visitNode(Leaf, std::forward<Args>(args)...); | 81 | 40 | } |
ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::CollectASTBuildOptions, void>::visitLeaf(isl::noexceptions::schedule_node const&) Line | Count | Source | 79 | 40 | RetTy visitLeaf(const isl::schedule_node &Leaf, Args... args) { | 80 | 40 | return getDerived().visitNode(Leaf, std::forward<Args>(args)...); | 81 | 40 | } |
|
82 | | |
83 | 160 | RetTy visitMark(const isl::schedule_node &Mark, Args... args) { |
84 | 160 | return getDerived().visitSingleChild(Mark, std::forward<Args>(args)...); |
85 | 160 | } ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::ApplyASTBuildOptions, isl::noexceptions::schedule_node>::visitMark(isl::noexceptions::schedule_node const&) Line | Count | Source | 83 | 80 | RetTy visitMark(const isl::schedule_node &Mark, Args... args) { | 84 | 80 | return getDerived().visitSingleChild(Mark, std::forward<Args>(args)...); | 85 | 80 | } |
ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::CollectASTBuildOptions, void>::visitMark(isl::noexceptions::schedule_node const&) Line | Count | Source | 83 | 80 | RetTy visitMark(const isl::schedule_node &Mark, Args... args) { | 84 | 80 | return getDerived().visitSingleChild(Mark, std::forward<Args>(args)...); | 85 | 80 | } |
|
86 | | |
87 | 24 | RetTy visitExtension(const isl::schedule_node &Extension, Args... args) { |
88 | 24 | return getDerived().visitSingleChild(Extension, |
89 | 24 | std::forward<Args>(args)...); |
90 | 24 | } Unexecuted instantiation: ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::ApplyASTBuildOptions, isl::noexceptions::schedule_node>::visitExtension(isl::noexceptions::schedule_node const&) ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::CollectASTBuildOptions, void>::visitExtension(isl::noexceptions::schedule_node const&) Line | Count | Source | 87 | 24 | RetTy visitExtension(const isl::schedule_node &Extension, Args... args) { | 88 | 24 | return getDerived().visitSingleChild(Extension, | 89 | 24 | std::forward<Args>(args)...); | 90 | 24 | } |
|
91 | | |
92 | 112 | RetTy visitFilter(const isl::schedule_node &Extension, Args... args) { |
93 | 112 | return getDerived().visitSingleChild(Extension, |
94 | 112 | std::forward<Args>(args)...); |
95 | 112 | } ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::ApplyASTBuildOptions, isl::noexceptions::schedule_node>::visitFilter(isl::noexceptions::schedule_node const&) Line | Count | Source | 92 | 56 | RetTy visitFilter(const isl::schedule_node &Extension, Args... args) { | 93 | 56 | return getDerived().visitSingleChild(Extension, | 94 | 56 | std::forward<Args>(args)...); | 95 | 56 | } |
ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::CollectASTBuildOptions, void>::visitFilter(isl::noexceptions::schedule_node const&) Line | Count | Source | 92 | 56 | RetTy visitFilter(const isl::schedule_node &Extension, Args... args) { | 93 | 56 | return getDerived().visitSingleChild(Extension, | 94 | 56 | std::forward<Args>(args)...); | 95 | 56 | } |
|
96 | | |
97 | 432 | RetTy visitSingleChild(const isl::schedule_node &Node, Args... args) { |
98 | 432 | return getDerived().visitNode(Node, std::forward<Args>(args)...); |
99 | 432 | } ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::ApplyASTBuildOptions, isl::noexceptions::schedule_node>::visitSingleChild(isl::noexceptions::schedule_node const&) Line | Count | Source | 97 | 204 | RetTy visitSingleChild(const isl::schedule_node &Node, Args... args) { | 98 | 204 | return getDerived().visitNode(Node, std::forward<Args>(args)...); | 99 | 204 | } |
ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::CollectASTBuildOptions, void>::visitSingleChild(isl::noexceptions::schedule_node const&) Line | Count | Source | 97 | 228 | RetTy visitSingleChild(const isl::schedule_node &Node, Args... args) { | 98 | 228 | return getDerived().visitNode(Node, std::forward<Args>(args)...); | 99 | 228 | } |
|
100 | | |
101 | 56 | RetTy visitMultiChild(const isl::schedule_node &Node, Args... args) { |
102 | 56 | return getDerived().visitNode(Node, std::forward<Args>(args)...); |
103 | 56 | } ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::ApplyASTBuildOptions, isl::noexceptions::schedule_node>::visitMultiChild(isl::noexceptions::schedule_node const&) Line | Count | Source | 101 | 28 | RetTy visitMultiChild(const isl::schedule_node &Node, Args... args) { | 102 | 28 | return getDerived().visitNode(Node, std::forward<Args>(args)...); | 103 | 28 | } |
ScheduleTreeTransform.cpp:(anonymous namespace)::ScheduleTreeVisitor<(anonymous namespace)::CollectASTBuildOptions, void>::visitMultiChild(isl::noexceptions::schedule_node const&) Line | Count | Source | 101 | 28 | RetTy visitMultiChild(const isl::schedule_node &Node, Args... args) { | 102 | 28 | return getDerived().visitNode(Node, std::forward<Args>(args)...); | 103 | 28 | } |
|
104 | | |
105 | | RetTy visitNode(const isl::schedule_node &Node, Args... args) { |
106 | | llvm_unreachable("Unimplemented other"); |
107 | | } |
108 | | }; |
109 | | |
110 | | /// Recursively visit all nodes of a schedule tree. |
111 | | template <typename Derived, typename RetTy = void, typename... Args> |
112 | | struct RecursiveScheduleTreeVisitor |
113 | | : public ScheduleTreeVisitor<Derived, RetTy, Args...> { |
114 | | using BaseTy = ScheduleTreeVisitor<Derived, RetTy, Args...>; |
115 | 864 | BaseTy &getBase() { return *this; } ScheduleTreeTransform.cpp:(anonymous namespace)::RecursiveScheduleTreeVisitor<(anonymous namespace)::ExtensionNodeRewriter, isl::noexceptions::schedule, isl::noexceptions::union_set const&, isl::noexceptions::union_map&>::getBase() Line | Count | Source | 115 | 296 | BaseTy &getBase() { return *this; } |
ScheduleTreeTransform.cpp:(anonymous namespace)::RecursiveScheduleTreeVisitor<(anonymous namespace)::ApplyASTBuildOptions, isl::noexceptions::schedule_node>::getBase() Line | Count | Source | 115 | 272 | BaseTy &getBase() { return *this; } |
ScheduleTreeTransform.cpp:(anonymous namespace)::RecursiveScheduleTreeVisitor<(anonymous namespace)::CollectASTBuildOptions, void>::getBase() Line | Count | Source | 115 | 296 | BaseTy &getBase() { return *this; } |
|
116 | | const BaseTy &getBase() const { return *this; } |
117 | 308 | Derived &getDerived() { return *static_cast<Derived *>(this); } ScheduleTreeTransform.cpp:(anonymous namespace)::RecursiveScheduleTreeVisitor<(anonymous namespace)::ApplyASTBuildOptions, isl::noexceptions::schedule_node>::getDerived() Line | Count | Source | 117 | 12 | Derived &getDerived() { return *static_cast<Derived *>(this); } |
ScheduleTreeTransform.cpp:(anonymous namespace)::RecursiveScheduleTreeVisitor<(anonymous namespace)::CollectASTBuildOptions, void>::getDerived() Line | Count | Source | 117 | 296 | Derived &getDerived() { return *static_cast<Derived *>(this); } |
|
118 | | const Derived &getDerived() const { |
119 | | return *static_cast<const Derived *>(this); |
120 | | } |
121 | | |
122 | | /// When visiting an entire schedule tree, start at its root node. |
123 | 24 | RetTy visit(const isl::schedule &Schedule, Args... args) { |
124 | 24 | return getDerived().visit(Schedule.get_root(), std::forward<Args>(args)...); |
125 | 24 | } ScheduleTreeTransform.cpp:(anonymous namespace)::RecursiveScheduleTreeVisitor<(anonymous namespace)::ApplyASTBuildOptions, isl::noexceptions::schedule_node>::visit(isl::noexceptions::schedule const&) Line | Count | Source | 123 | 12 | RetTy visit(const isl::schedule &Schedule, Args... args) { | 124 | 12 | return getDerived().visit(Schedule.get_root(), std::forward<Args>(args)...); | 125 | 12 | } |
ScheduleTreeTransform.cpp:(anonymous namespace)::RecursiveScheduleTreeVisitor<(anonymous namespace)::CollectASTBuildOptions, void>::visit(isl::noexceptions::schedule const&) Line | Count | Source | 123 | 12 | RetTy visit(const isl::schedule &Schedule, Args... args) { | 124 | 12 | return getDerived().visit(Schedule.get_root(), std::forward<Args>(args)...); | 125 | 12 | } |
|
126 | | |
127 | | // Necessary to allow overload resolution with the added visit(isl::schedule) |
128 | | // overload. |
129 | 864 | RetTy visit(const isl::schedule_node &Node, Args... args) { |
130 | 864 | return getBase().visit(Node, std::forward<Args>(args)...); |
131 | 864 | } ScheduleTreeTransform.cpp:(anonymous namespace)::RecursiveScheduleTreeVisitor<(anonymous namespace)::ExtensionNodeRewriter, isl::noexceptions::schedule, isl::noexceptions::union_set const&, isl::noexceptions::union_map&>::visit(isl::noexceptions::schedule_node const&, isl::noexceptions::union_set const&, isl::noexceptions::union_map&) Line | Count | Source | 129 | 296 | RetTy visit(const isl::schedule_node &Node, Args... args) { | 130 | 296 | return getBase().visit(Node, std::forward<Args>(args)...); | 131 | 296 | } |
ScheduleTreeTransform.cpp:(anonymous namespace)::RecursiveScheduleTreeVisitor<(anonymous namespace)::ApplyASTBuildOptions, isl::noexceptions::schedule_node>::visit(isl::noexceptions::schedule_node const&) Line | Count | Source | 129 | 272 | RetTy visit(const isl::schedule_node &Node, Args... args) { | 130 | 272 | return getBase().visit(Node, std::forward<Args>(args)...); | 131 | 272 | } |
ScheduleTreeTransform.cpp:(anonymous namespace)::RecursiveScheduleTreeVisitor<(anonymous namespace)::CollectASTBuildOptions, void>::visit(isl::noexceptions::schedule_node const&) Line | Count | Source | 129 | 296 | RetTy visit(const isl::schedule_node &Node, Args... args) { | 130 | 296 | return getBase().visit(Node, std::forward<Args>(args)...); | 131 | 296 | } |
|
132 | | |
133 | 296 | RetTy visitNode(const isl::schedule_node &Node, Args... args) { |
134 | 296 | int NumChildren = isl_schedule_node_n_children(Node.get()); |
135 | 580 | for (int i = 0; i < NumChildren; i += 1284 ) |
136 | 284 | getDerived().visit(Node.child(i), std::forward<Args>(args)...); |
137 | 296 | return RetTy(); |
138 | 296 | } |
139 | | }; |
140 | | |
141 | | /// Recursively visit all nodes of a schedule tree while allowing changes. |
142 | | /// |
143 | | /// The visit methods return an isl::schedule_node that is used to continue |
144 | | /// visiting the tree. Structural changes such as returning a different node |
145 | | /// will confuse the visitor. |
146 | | template <typename Derived, typename... Args> |
147 | | struct ScheduleNodeRewriter |
148 | | : public RecursiveScheduleTreeVisitor<Derived, isl::schedule_node, |
149 | | Args...> { |
150 | 260 | Derived &getDerived() { return *static_cast<Derived *>(this); } |
151 | | const Derived &getDerived() const { |
152 | | return *static_cast<const Derived *>(this); |
153 | | } |
154 | | |
155 | 272 | isl::schedule_node visitNode(const isl::schedule_node &Node, Args... args) { |
156 | 272 | if (!Node.has_children()) |
157 | 40 | return Node; |
158 | 232 | |
159 | 232 | isl::schedule_node It = Node.first_child(); |
160 | 260 | while (true) { |
161 | 260 | It = getDerived().visit(It, std::forward<Args>(args)...); |
162 | 260 | if (!It.has_next_sibling()) |
163 | 232 | break; |
164 | 28 | It = It.next_sibling(); |
165 | 28 | } |
166 | 232 | return It.parent(); |
167 | 232 | } |
168 | | }; |
169 | | |
170 | | /// Rewrite a schedule tree by reconstructing it bottom-up. |
171 | | /// |
172 | | /// By default, the original schedule tree is reconstructed. To build a |
173 | | /// different tree, redefine visitor methods in a derived class (CRTP). |
174 | | /// |
175 | | /// Note that AST build options are not applied; Setting the isolate[] option |
176 | | /// makes the schedule tree 'anchored' and cannot be modified afterwards. Hence, |
177 | | /// AST build options must be set after the tree has been constructed. |
178 | | template <typename Derived, typename... Args> |
179 | | struct ScheduleTreeRewriter |
180 | | : public RecursiveScheduleTreeVisitor<Derived, isl::schedule, Args...> { |
181 | 92 | Derived &getDerived() { return *static_cast<Derived *>(this); } |
182 | | const Derived &getDerived() const { |
183 | | return *static_cast<const Derived *>(this); |
184 | | } |
185 | | |
186 | 12 | isl::schedule visitDomain(const isl::schedule_node &Node, Args... args) { |
187 | 12 | // Every schedule_tree already has a domain node, no need to add one. |
188 | 12 | return getDerived().visit(Node.first_child(), std::forward<Args>(args)...); |
189 | 12 | } |
190 | | |
191 | | isl::schedule visitBand(const isl::schedule_node &Band, Args... args) { |
192 | | isl::multi_union_pw_aff PartialSched = |
193 | | isl::manage(isl_schedule_node_band_get_partial_schedule(Band.get())); |
194 | | isl::schedule NewChild = |
195 | | getDerived().visit(Band.child(0), std::forward<Args>(args)...); |
196 | | isl::schedule_node NewNode = |
197 | | NewChild.insert_partial_schedule(PartialSched).get_root().get_child(0); |
198 | | |
199 | | // Reapply permutability and coincidence attributes. |
200 | | NewNode = isl::manage(isl_schedule_node_band_set_permutable( |
201 | | NewNode.release(), isl_schedule_node_band_get_permutable(Band.get()))); |
202 | | unsigned BandDims = isl_schedule_node_band_n_member(Band.get()); |
203 | | for (unsigned i = 0; i < BandDims; i += 1) |
204 | | NewNode = isl::manage(isl_schedule_node_band_member_set_coincident( |
205 | | NewNode.release(), i, |
206 | | isl_schedule_node_band_member_get_coincident(Band.get(), i))); |
207 | | |
208 | | return NewNode.get_schedule(); |
209 | | } |
210 | | |
211 | | isl::schedule visitSequence(const isl::schedule_node &Sequence, |
212 | | Args... args) { |
213 | | int NumChildren = isl_schedule_node_n_children(Sequence.get()); |
214 | | isl::schedule Result = |
215 | | getDerived().visit(Sequence.child(0), std::forward<Args>(args)...); |
216 | | for (int i = 1; i < NumChildren; i += 1) |
217 | | Result = Result.sequence( |
218 | | getDerived().visit(Sequence.child(i), std::forward<Args>(args)...)); |
219 | | return Result; |
220 | | } |
221 | | |
222 | | isl::schedule visitSet(const isl::schedule_node &Set, Args... args) { |
223 | | int NumChildren = isl_schedule_node_n_children(Set.get()); |
224 | | isl::schedule Result = |
225 | | getDerived().visit(Set.child(0), std::forward<Args>(args)...); |
226 | | for (int i = 1; i < NumChildren; i += 1) |
227 | | Result = isl::manage( |
228 | | isl_schedule_set(Result.release(), |
229 | | getDerived() |
230 | | .visit(Set.child(i), std::forward<Args>(args)...) |
231 | | .release())); |
232 | | return Result; |
233 | | } |
234 | | |
235 | | isl::schedule visitLeaf(const isl::schedule_node &Leaf, Args... args) { |
236 | | return isl::schedule::from_domain(Leaf.get_domain()); |
237 | | } |
238 | | |
239 | 80 | isl::schedule visitMark(const isl::schedule_node &Mark, Args... args) { |
240 | 80 | isl::id TheMark = Mark.mark_get_id(); |
241 | 80 | isl::schedule_node NewChild = |
242 | 80 | getDerived() |
243 | 80 | .visit(Mark.first_child(), std::forward<Args>(args)...) |
244 | 80 | .get_root() |
245 | 80 | .first_child(); |
246 | 80 | return NewChild.insert_mark(TheMark).get_schedule(); |
247 | 80 | } |
248 | | |
249 | | isl::schedule visitExtension(const isl::schedule_node &Extension, |
250 | | Args... args) { |
251 | | isl::union_map TheExtension = Extension.extension_get_extension(); |
252 | | isl::schedule_node NewChild = getDerived() |
253 | | .visit(Extension.child(0), args...) |
254 | | .get_root() |
255 | | .first_child(); |
256 | | isl::schedule_node NewExtension = |
257 | | isl::schedule_node::from_extension(TheExtension); |
258 | | return NewChild.graft_before(NewExtension).get_schedule(); |
259 | | } |
260 | | |
261 | | isl::schedule visitFilter(const isl::schedule_node &Filter, Args... args) { |
262 | | isl::union_set FilterDomain = Filter.filter_get_filter(); |
263 | | isl::schedule NewSchedule = |
264 | | getDerived().visit(Filter.child(0), std::forward<Args>(args)...); |
265 | | return NewSchedule.intersect_domain(FilterDomain); |
266 | | } |
267 | | |
268 | | isl::schedule visitNode(const isl::schedule_node &Node, Args... args) { |
269 | | llvm_unreachable("Not implemented"); |
270 | | } |
271 | | }; |
272 | | |
273 | | /// Rewrite a schedule tree to an equivalent one without extension nodes. |
274 | | /// |
275 | | /// Each visit method takes two additional arguments: |
276 | | /// |
277 | | /// * The new domain the node, which is the inherited domain plus any domains |
278 | | /// added by extension nodes. |
279 | | /// |
280 | | /// * A map of extension domains of all children is returned; it is required by |
281 | | /// band nodes to schedule the additional domains at the same position as the |
282 | | /// extension node would. |
283 | | /// |
284 | | struct ExtensionNodeRewriter |
285 | | : public ScheduleTreeRewriter<ExtensionNodeRewriter, const isl::union_set &, |
286 | | isl::union_map &> { |
287 | | using BaseTy = ScheduleTreeRewriter<ExtensionNodeRewriter, |
288 | | const isl::union_set &, isl::union_map &>; |
289 | 0 | BaseTy &getBase() { return *this; } |
290 | 0 | const BaseTy &getBase() const { return *this; } |
291 | | |
292 | 12 | isl::schedule visitSchedule(const isl::schedule &Schedule) { |
293 | 12 | isl::union_map Extensions; |
294 | 12 | isl::schedule Result = |
295 | 12 | visit(Schedule.get_root(), Schedule.get_domain(), Extensions); |
296 | 12 | assert(Extensions && Extensions.is_empty()); |
297 | 12 | return Result; |
298 | 12 | } |
299 | | |
300 | | isl::schedule visitSequence(const isl::schedule_node &Sequence, |
301 | | const isl::union_set &Domain, |
302 | 28 | isl::union_map &Extensions) { |
303 | 28 | int NumChildren = isl_schedule_node_n_children(Sequence.get()); |
304 | 28 | isl::schedule NewNode = visit(Sequence.first_child(), Domain, Extensions); |
305 | 56 | for (int i = 1; i < NumChildren; i += 128 ) { |
306 | 28 | isl::schedule_node OldChild = Sequence.child(i); |
307 | 28 | isl::union_map NewChildExtensions; |
308 | 28 | isl::schedule NewChildNode = visit(OldChild, Domain, NewChildExtensions); |
309 | 28 | NewNode = NewNode.sequence(NewChildNode); |
310 | 28 | Extensions = Extensions.unite(NewChildExtensions); |
311 | 28 | } |
312 | 28 | return NewNode; |
313 | 28 | } |
314 | | |
315 | | isl::schedule visitSet(const isl::schedule_node &Set, |
316 | | const isl::union_set &Domain, |
317 | 0 | isl::union_map &Extensions) { |
318 | 0 | int NumChildren = isl_schedule_node_n_children(Set.get()); |
319 | 0 | isl::schedule NewNode = visit(Set.first_child(), Domain, Extensions); |
320 | 0 | for (int i = 1; i < NumChildren; i += 1) { |
321 | 0 | isl::schedule_node OldChild = Set.child(i); |
322 | 0 | isl::union_map NewChildExtensions; |
323 | 0 | isl::schedule NewChildNode = visit(OldChild, Domain, NewChildExtensions); |
324 | 0 | NewNode = isl::manage( |
325 | 0 | isl_schedule_set(NewNode.release(), NewChildNode.release())); |
326 | 0 | Extensions = Extensions.unite(NewChildExtensions); |
327 | 0 | } |
328 | 0 | return NewNode; |
329 | 0 | } |
330 | | |
331 | | isl::schedule visitLeaf(const isl::schedule_node &Leaf, |
332 | | const isl::union_set &Domain, |
333 | 40 | isl::union_map &Extensions) { |
334 | 40 | isl::ctx Ctx = Leaf.get_ctx(); |
335 | 40 | Extensions = isl::union_map::empty(isl::space::params_alloc(Ctx, 0)); |
336 | 40 | return isl::schedule::from_domain(Domain); |
337 | 40 | } |
338 | | |
339 | | isl::schedule visitBand(const isl::schedule_node &OldNode, |
340 | | const isl::union_set &Domain, |
341 | 56 | isl::union_map &OuterExtensions) { |
342 | 56 | isl::schedule_node OldChild = OldNode.first_child(); |
343 | 56 | isl::multi_union_pw_aff PartialSched = |
344 | 56 | isl::manage(isl_schedule_node_band_get_partial_schedule(OldNode.get())); |
345 | 56 | |
346 | 56 | isl::union_map NewChildExtensions; |
347 | 56 | isl::schedule NewChild = visit(OldChild, Domain, NewChildExtensions); |
348 | 56 | |
349 | 56 | // Add the extensions to the partial schedule. |
350 | 56 | OuterExtensions = isl::union_map::empty(NewChildExtensions.get_space()); |
351 | 56 | isl::union_map NewPartialSchedMap = isl::union_map::from(PartialSched); |
352 | 56 | unsigned BandDims = isl_schedule_node_band_n_member(OldNode.get()); |
353 | 56 | for (isl::map Ext : NewChildExtensions.get_map_list()) { |
354 | 36 | unsigned ExtDims = Ext.dim(isl::dim::in); |
355 | 36 | assert(ExtDims >= BandDims); |
356 | 36 | unsigned OuterDims = ExtDims - BandDims; |
357 | 36 | |
358 | 36 | isl::map BandSched = |
359 | 36 | Ext.project_out(isl::dim::in, 0, OuterDims).reverse(); |
360 | 36 | NewPartialSchedMap = NewPartialSchedMap.unite(BandSched); |
361 | 36 | |
362 | 36 | // There might be more outer bands that have to schedule the extensions. |
363 | 36 | if (OuterDims > 0) { |
364 | 12 | isl::map OuterSched = |
365 | 12 | Ext.project_out(isl::dim::in, OuterDims, BandDims); |
366 | 12 | OuterExtensions = OuterExtensions.add_map(OuterSched); |
367 | 12 | } |
368 | 36 | } |
369 | 56 | isl::multi_union_pw_aff NewPartialSchedAsAsMultiUnionPwAff = |
370 | 56 | isl::multi_union_pw_aff::from_union_map(NewPartialSchedMap); |
371 | 56 | isl::schedule_node NewNode = |
372 | 56 | NewChild.insert_partial_schedule(NewPartialSchedAsAsMultiUnionPwAff) |
373 | 56 | .get_root() |
374 | 56 | .get_child(0); |
375 | 56 | |
376 | 56 | // Reapply permutability and coincidence attributes. |
377 | 56 | NewNode = isl::manage(isl_schedule_node_band_set_permutable( |
378 | 56 | NewNode.release(), |
379 | 56 | isl_schedule_node_band_get_permutable(OldNode.get()))); |
380 | 180 | for (unsigned i = 0; i < BandDims; i += 1124 ) { |
381 | 124 | NewNode = isl::manage(isl_schedule_node_band_member_set_coincident( |
382 | 124 | NewNode.release(), i, |
383 | 124 | isl_schedule_node_band_member_get_coincident(OldNode.get(), i))); |
384 | 124 | } |
385 | 56 | |
386 | 56 | return NewNode.get_schedule(); |
387 | 56 | } |
388 | | |
389 | | isl::schedule visitFilter(const isl::schedule_node &Filter, |
390 | | const isl::union_set &Domain, |
391 | 56 | isl::union_map &Extensions) { |
392 | 56 | isl::union_set FilterDomain = Filter.filter_get_filter(); |
393 | 56 | isl::union_set NewDomain = Domain.intersect(FilterDomain); |
394 | 56 | |
395 | 56 | // A filter is added implicitly if necessary when joining schedule trees. |
396 | 56 | return visit(Filter.first_child(), NewDomain, Extensions); |
397 | 56 | } |
398 | | |
399 | | isl::schedule visitExtension(const isl::schedule_node &Extension, |
400 | | const isl::union_set &Domain, |
401 | 24 | isl::union_map &Extensions) { |
402 | 24 | isl::union_map ExtDomain = Extension.extension_get_extension(); |
403 | 24 | isl::union_set NewDomain = Domain.unite(ExtDomain.range()); |
404 | 24 | isl::union_map ChildExtensions; |
405 | 24 | isl::schedule NewChild = |
406 | 24 | visit(Extension.first_child(), NewDomain, ChildExtensions); |
407 | 24 | Extensions = ChildExtensions.unite(ExtDomain); |
408 | 24 | return NewChild; |
409 | 24 | } |
410 | | }; |
411 | | |
412 | | /// Collect all AST build options in any schedule tree band. |
413 | | /// |
414 | | /// ScheduleTreeRewriter cannot apply the schedule tree options. This class |
415 | | /// collects these options to apply them later. |
416 | | struct CollectASTBuildOptions |
417 | | : public RecursiveScheduleTreeVisitor<CollectASTBuildOptions> { |
418 | | using BaseTy = RecursiveScheduleTreeVisitor<CollectASTBuildOptions>; |
419 | 56 | BaseTy &getBase() { return *this; } |
420 | 0 | const BaseTy &getBase() const { return *this; } |
421 | | |
422 | | llvm::SmallVector<isl::union_set, 8> ASTBuildOptions; |
423 | | |
424 | 56 | void visitBand(const isl::schedule_node &Band) { |
425 | 56 | ASTBuildOptions.push_back( |
426 | 56 | isl::manage(isl_schedule_node_band_get_ast_build_options(Band.get()))); |
427 | 56 | return getBase().visitBand(Band); |
428 | 56 | } |
429 | | }; |
430 | | |
431 | | /// Apply AST build options to the bands in a schedule tree. |
432 | | /// |
433 | | /// This rewrites a schedule tree with the AST build options applied. We assume |
434 | | /// that the band nodes are visited in the same order as they were when the |
435 | | /// build options were collected, typically by CollectASTBuildOptions. |
436 | | struct ApplyASTBuildOptions |
437 | | : public ScheduleNodeRewriter<ApplyASTBuildOptions> { |
438 | | using BaseTy = ScheduleNodeRewriter<ApplyASTBuildOptions>; |
439 | 56 | BaseTy &getBase() { return *this; } |
440 | 0 | const BaseTy &getBase() const { return *this; } |
441 | | |
442 | | size_t Pos; |
443 | | llvm::ArrayRef<isl::union_set> ASTBuildOptions; |
444 | | |
445 | | ApplyASTBuildOptions(llvm::ArrayRef<isl::union_set> ASTBuildOptions) |
446 | 12 | : ASTBuildOptions(ASTBuildOptions) {} |
447 | | |
448 | 12 | isl::schedule visitSchedule(const isl::schedule &Schedule) { |
449 | 12 | Pos = 0; |
450 | 12 | isl::schedule Result = visit(Schedule).get_schedule(); |
451 | 12 | assert(Pos == ASTBuildOptions.size() && |
452 | 12 | "AST build options must match to band nodes"); |
453 | 12 | return Result; |
454 | 12 | } |
455 | | |
456 | 56 | isl::schedule_node visitBand(const isl::schedule_node &Band) { |
457 | 56 | isl::schedule_node Result = |
458 | 56 | Band.band_set_ast_build_options(ASTBuildOptions[Pos]); |
459 | 56 | Pos += 1; |
460 | 56 | return getBase().visitBand(Result); |
461 | 56 | } |
462 | | }; |
463 | | |
464 | | } // namespace |
465 | | |
466 | | /// Return whether the schedule contains an extension node. |
467 | 40 | static bool containsExtensionNode(isl::schedule Schedule) { |
468 | 40 | assert(!Schedule.is_null()); |
469 | 40 | |
470 | 40 | auto Callback = [](__isl_keep isl_schedule_node *Node, |
471 | 412 | void *User) -> isl_bool { |
472 | 412 | if (isl_schedule_node_get_type(Node) == isl_schedule_node_extension) { |
473 | 12 | // Stop walking the schedule tree. |
474 | 12 | return isl_bool_error; |
475 | 12 | } |
476 | 400 | |
477 | 400 | // Continue searching the subtree. |
478 | 400 | return isl_bool_true; |
479 | 400 | }; |
480 | 40 | isl_stat RetVal = isl_schedule_foreach_schedule_node_top_down( |
481 | 40 | Schedule.get(), Callback, nullptr); |
482 | 40 | |
483 | 40 | // We assume that the traversal itself does not fail, i.e. the only reason to |
484 | 40 | // return isl_stat_error is that an extension node was found. |
485 | 40 | return RetVal == isl_stat_error; |
486 | 40 | } |
487 | | |
488 | 40 | isl::schedule polly::hoistExtensionNodes(isl::schedule Sched) { |
489 | 40 | // If there is no extension node in the first place, return the original |
490 | 40 | // schedule tree. |
491 | 40 | if (!containsExtensionNode(Sched)) |
492 | 28 | return Sched; |
493 | 12 | |
494 | 12 | // Build options can anchor schedule nodes, such that the schedule tree cannot |
495 | 12 | // be modified anymore. Therefore, apply build options after the tree has been |
496 | 12 | // created. |
497 | 12 | CollectASTBuildOptions Collector; |
498 | 12 | Collector.visit(Sched); |
499 | 12 | |
500 | 12 | // Rewrite the schedule tree without extension nodes. |
501 | 12 | ExtensionNodeRewriter Rewriter; |
502 | 12 | isl::schedule NewSched = Rewriter.visitSchedule(Sched); |
503 | 12 | |
504 | 12 | // Reapply the AST build options. The rewriter must not change the iteration |
505 | 12 | // order of bands. Any other node type is ignored. |
506 | 12 | ApplyASTBuildOptions Applicator(Collector.ASTBuildOptions); |
507 | 12 | NewSched = Applicator.visitSchedule(NewSched); |
508 | 12 | |
509 | 12 | return NewSched; |
510 | 12 | } |