Coverage Report

Created: 2019-07-24 05:18

/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
}