CACAO
PassManager.cpp
Go to the documentation of this file.
1 /* src/vm/jit/compiler2/PassManager.cpp - PassManager
2 
3  Copyright (C) 2013
4  CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5 
6  This file is part of CACAO.
7 
8  This program is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2, or (at
11  your option) any later version.
12 
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  02110-1301, USA.
22 
23 */
24 
29 #include "toolbox/logging.hpp"
30 #include "toolbox/Option.hpp"
31 #include "vm/vm.hpp"
35 
36 #include "vm/rt-timing.hpp"
37 
38 #include <algorithm>
39 
40 #define DEBUG_NAME "compiler2/PassManager"
41 
42 namespace cacao {
43 namespace jit {
44 namespace compiler2 {
45 
46 #if ENABLE_RT_TIMING
47 namespace {
48 RT_REGISTER_GROUP(compiler2_rtgroup,"compiler2-pipeline","compiler2 pass pipeline")
49 
50 typedef alloc::unordered_map<PassInfo::IDTy,RTTimer>::type PassTimerMap;
51 PassTimerMap pass_timers;
52 
53 } // end anonymous namespace
54 #endif
55 
56 namespace {
57 namespace option {
58  Option<bool> print_pass_dependencies("PrintPassDependencies","compiler2: print pass dependencies",false,::cacao::option::xx_root());
59 }
60 } // end anonymous namespace
61 
62 
64  PassInfo *PI = registered_passes()[ID];
65  assert(PI && "Pass not registered");
66 
67  // This should be the only place where a Pass is constructed!
68  PassUPtrTy pass(PI->create_Pass());
69 
70  #if ENABLE_RT_TIMING
71  RTTimer &timer = pass_timers[ID];
72  new (&timer) RTTimer(PI->get_name(),PI->get_name(),compiler2_rtgroup());
73  #endif
74 
75  return pass;
76 }
77 
78 // Since passes do NOT guarantee that they can be reused cleanly
79 // we create new pass instances if they occur more than once in the schedule
81  auto P = PassManager::get().create_Pass(ID);
82  P->set_PassRunner(this);
83 
84  passes[ID] = std::move(P);
85  result_ready[ID] = false;
86 
87  return passes[ID];
88 }
89 
90 
92  LOG("runPasses" << nl);
93 
94  auto PS = PassManager::get();
95  for (auto i = PS.schedule_begin(), e = PS.schedule_end(); i != e; ++i) {
96  PassInfo::IDTy id = *i;
97  result_ready[id] = false;
98  #if ENABLE_RT_TIMING
99  PassTimerMap::iterator f = pass_timers.find(id);
100  assert(f != pass_timers.end());
101  RTTimer &timer = f->second;
102  timer.start();
103  #endif
104  auto&& P = get_Pass(id);
105  LOG("initialize: " << PS.get_Pass_name(id) << nl);
106  P->initialize();
107  LOG("start: " << PS.get_Pass_name(id) << nl);
108  if (!P->run(JD)) {
109  err() << bold << Red << "error" << reset_color << " during pass " << PS.get_Pass_name(id) << nl;
110  os::abort("compiler2: error");
111  }
112  // invalidating results
113  PassUsage PU;
114  PU = P->get_PassUsage(PU);
116  i != e; ++i) {
117  result_ready[*i] = false;
118  LOG("mark invalid" << PS.get_Pass_name(*i) << nl);
119  }
120  #ifndef NDEBUG
121  LOG("verifying: " << PS.get_Pass_name(id) << nl);
122  if (!P->verify()) {
123  err() << bold << Red << "verification error" << reset_color << " during pass " << PS.get_Pass_name(id) << nl;
124  os::abort("compiler2: error");
125  }
126  #endif
127  result_ready[id] = true;
128  LOG("finialize: " << PS.get_Pass_name(id) << nl);
129  P->finalize();
130  #if ENABLE_RT_TIMING
131  timer.stop();
132  #endif
133  }
134 }
135 
136 
137 // begin Pass scheduler
138 
139 #undef DEBUG_NAME
140 #define DEBUG_NAME "compiler2/PassManager/Scheduler"
141 namespace {
142 
143 #if defined(ENABLE_LOGGING) || !defined(NDEBUG)
144 // XXX for debugging only, to be removed
145 PassManager* latest = NULL;
146 // XXX for debugging only, to be removed
147 const char* get_Pass_name(PassInfo::IDTy id) {
148  if (!latest) return "PassManager not available";
149  return latest->get_Pass_name(id);
150 }
151 #endif // defined(ENABLE_LOGGING) || !defined(NDEBUG)
152 
153 template <class InputIterator, class ValueType>
154 inline bool contains(InputIterator begin, InputIterator end, const ValueType &val) {
155  return std::find(begin,end,val) != end;
156 }
157 
158 template <class Container, class ValueType>
159 struct ContainsFn {
160  bool operator()(const Container &c, const ValueType &val) {
161  return contains(c.begin(),c.end(),val);
162  }
163 };
164 
165 template <class ValueType>
166 struct ContainsFn<typename alloc::set<ValueType>::type,ValueType> {
167  bool operator()(const typename alloc::set<ValueType>::type &c, const ValueType &val) {
168  return c.find(val) != c.end();
169  }
170 };
171 
172 template <class ValueType>
173 struct ContainsFn<alloc::unordered_set<ValueType>,ValueType> {
174  bool operator()(const typename alloc::unordered_set<ValueType>::type &c, const ValueType &val) {
175  return c.find(val) != c.end();
176  }
177 };
178 
179 template <class Container, class ValueType>
180 inline bool contains(const Container &c, const ValueType &val) {
181  return ContainsFn<Container,ValueType>()(c,val);
182 }
183 
184 
185 typedef alloc::unordered_map<PassInfo::IDTy,PassUsage>::type ID2PUTy;
186 typedef alloc::unordered_map<PassInfo::IDTy,alloc::unordered_set<PassInfo::IDTy>::type >::type ID2MapTy;
187 
188 struct Invalidate :
189 public std::unary_function<PassInfo::IDTy,void> {
192  // constructor
194  : reverse_require_map(reverse_require_map), ready(ready) {}
195  // function call operator
196  void operator()(PassInfo::IDTy id) {
197  if (ready.erase(id)) {
198  LOG3(" invalidated: " << get_Pass_name(id) << nl);
199  std::for_each(reverse_require_map[id].begin(),reverse_require_map[id].end(),*this);
200  }
201  }
202 };
203 
204 class PassScheduler {
205 private:
206  alloc::deque<PassInfo::IDTy>::type &unhandled;
208  alloc::list<PassInfo::IDTy>::type &stack;
210  ID2PUTy &pu_map;
211  ID2MapTy &reverse_require_map;
212 public:
213  /// constructor
214  PassScheduler(alloc::deque<PassInfo::IDTy>::type &unhandled, alloc::unordered_set<PassInfo::IDTy>::type &ready,
215  alloc::list<PassInfo::IDTy>::type &stack, PassManager::ScheduleListTy &new_schedule,
216  ID2PUTy &pu_map, ID2MapTy &reverse_require_map)
217  : unhandled(unhandled), ready(ready), stack(stack), new_schedule(new_schedule),
218  pu_map(pu_map), reverse_require_map(reverse_require_map) {}
219  /// call operator
220  void operator()(PassInfo::IDTy id) {
221  if (contains(ready,id)) return;
222  #ifndef NDEBUG
223  if (contains(stack,id)) {
224  ABORT_MSG("PassManager: dependency cycle detected",
225  "Pass " << get_Pass_name(id) << " already stacked for scheduling!");
226  }
227  #endif
228  stack.push_back(id);
229  PassUsage &PU = pu_map[id];
230  LOG3("prescheduled: " << get_Pass_name(id) << nl);
231  bool fixpoint;
232  do {
233  fixpoint = true;
234  // schedule schedule_after
235  for (PassUsage::const_iterator i = PU.schedule_after_begin(), e = PU.schedule_after_end();
236  i != e ; ++i) {
237  LOG3(" schedule_after: " << get_Pass_name(*i) << nl);
238  if (std::find(new_schedule.rbegin(),new_schedule.rend(),*i) == new_schedule.rend()) {
239  operator()(*i);
240  fixpoint = false;
241  }
242  }
243  // schedule requires
244  for (PassUsage::const_iterator i = PU.requires_begin(), e = PU.requires_end();
245  i != e ; ++i) {
246  LOG3(" requires: " << get_Pass_name(*i) << nl);
247  if (ready.find(*i) == ready.end()) {
248  operator()(*i);
249  fixpoint = false;
250  }
251  }
252  } while(!fixpoint);
253 
254  LOG3("scheduled: " << get_Pass_name(id) << nl);
255  // remove all destroyed passes from ready
256  std::for_each(PU.destroys_begin(),PU.destroys_end(),Invalidate(reverse_require_map,ready));
257  // remove all passed depending on modified from ready
258  for (PassUsage::const_iterator i = PU.modifies_begin(), e = PU.modifies_end();
259  i != e ; ++i) {
260  if (ready.find(*i) != ready.end()) {
261  LOG3(" modifies: " << get_Pass_name(*i) << nl);
262  std::for_each(reverse_require_map[*i].begin(),reverse_require_map[*i].end(),
263  Invalidate(reverse_require_map,ready));
264  }
265  }
266  // dummy use
267  unhandled.front();
268  new_schedule.push_back(id);
269  ready.insert(id);
270  stack.pop_back();
271  }
272 };
273 
274 struct RunBefore : public std::unary_function<PassInfo::IDTy,void> {
275  ID2PUTy &pu_map;
277 
278  RunBefore(ID2PUTy &pu_map, PassInfo::IDTy id)
279  : pu_map(pu_map), id(id) {}
280 
281  void operator()(PassInfo::IDTy before) {
282  //pu_map[before].add_schedule_after(id);
283  pu_map[before].add_requires(id);
284  }
285 };
286 
287 struct ScheduleBefore : public std::unary_function<PassInfo::IDTy,void> {
288  ID2PUTy &pu_map;
290 
291  ScheduleBefore(ID2PUTy &pu_map, PassInfo::IDTy id)
292  : pu_map(pu_map), id(id) {}
293 
294  void operator()(PassInfo::IDTy before) {
295  pu_map[before].add_schedule_after(id);
296  }
297 };
298 
299 struct AddReverseRequire : public std::unary_function<PassInfo::IDTy,void> {
300  ID2MapTy &map;
302 
303  AddReverseRequire(ID2MapTy &map, PassInfo::IDTy id)
304  : map(map), id(id) {}
305 
306  void operator()(PassInfo::IDTy required_by) {
307  map[required_by].insert(id);
308  }
309 };
310 
311 struct ReverseRequire :
312 public std::unary_function<ID2PUTy::value_type,void> {
313  ID2MapTy &map;
314  // constructor
315  ReverseRequire(ID2MapTy &map) : map(map) {}
316  // function call operator
317  void operator()(argument_type pair) {
318  std::for_each(pair.second.requires_begin(), pair.second.requires_end(),AddReverseRequire(map,pair.first));
319  }
320 };
321 
322 } // end anonymous namespace
323 
325 #if defined(ENABLE_LOGGING) || !defined(NDEBUG)
326  // XXX for debugging only, to be removed
327  latest = this;
328 #endif
329 
330  if (option::print_pass_dependencies) {
332  }
333 
338  ID2PUTy pu_map;
339  ID2MapTy reverse_require_map;
340 
341  for (PassInfoMapTy::const_iterator i = registered_passes().begin(), e = registered_passes().end();
342  i != e; ++i) {
343  PassInfo::IDTy id = i->first;
344  auto pass = create_Pass(id);
345 
346  // Only schedule passes that want to be run
347  if (!pass->is_enabled()) {
348  continue;
349  }
350 
351  // If a pass is enabled, add it to the schedule
352  schedule.push_back(id);
353 
354  PassUsage &PA = pu_map[id];
355  pass->get_PassUsage(PA);
356  // add run before
357  std::for_each(PA.run_before_begin(),PA.run_before_end(),RunBefore(pu_map,id));
358  // add schedule before
359  std::for_each(PA.schedule_before_begin(),PA.schedule_before_end(),ScheduleBefore(pu_map,id));
360  }
361  // fill reverser required map
362  std::for_each(pu_map.begin(),pu_map.end(),ReverseRequire(reverse_require_map));
363  std::copy(schedule.begin(), schedule.end(), std::back_inserter(unhandled));
364 
365  PassScheduler scheduler(unhandled,ready,stack,new_schedule,pu_map,reverse_require_map);
366  while (!unhandled.empty()) {
367  PassInfo::IDTy id = unhandled.front();
368  unhandled.pop_front();
369  // schedule
370  scheduler(id);
371  assert(stack.empty());
372  }
373 
374  if (DEBUG_COND_N(2)) {
375  LOG2("old Schedule:" << nl);
376  for (ScheduleListTy::const_iterator i = schedule.begin(),
377  e = schedule.end(); i != e ; ++i) {
378  LOG2(" " << get_Pass_name(*i) << " id: " << *i << nl);
379  }
380  LOG2("new Schedule:" << nl);
381  for (ScheduleListTy::const_iterator i = new_schedule.begin(),
382  e = new_schedule.end(); i != e ; ++i) {
383  LOG2(" " << get_Pass_name(*i) << " id: " << *i << nl);
384  }
385  }
387 }
388 } // end namespace cacao
389 } // end namespace jit
390 } // end namespace compiler2
391 
392 /*
393  * These are local overrides for various environment variables in Emacs.
394  * Please do not remove this and leave it at the end of the file, where
395  * Emacs will automagically detect them.
396  * ---------------------------------------------------------------------
397  * Local variables:
398  * mode: c++
399  * indent-tabs-mode: t
400  * c-basic-offset: 4
401  * tab-width: 4
402  * End:
403  * vim:noexpandtab:sw=4:ts=4:
404  */
ID2MapTy & reverse_require_map
PassUPtrTy & get_Pass(PassInfo::IDTy ID)
Definition: PassManager.cpp:80
std::unique_ptr< Pass > PassUPtrTy
Definition: PassManager.hpp:53
ID2PUTy & pu_map
ResultReadyMapTy result_ready
Map of ready results.
const_iterator destroys_end() const
Definition: PassUsage.hpp:151
std::deque< T, Allocator< T > > type
Definition: deque.hpp:38
PassInfo::IDTy id
alloc::vector< PassInfo::IDTy >::type ScheduleListTy
Definition: PassManager.hpp:89
#define DEBUG_COND_N(VERBOSE)
Definition: Debug.hpp:112
std::unordered_set< PassInfo::IDTy, std::hash< PassInfo::IDTy >, std::equal_to< PassInfo::IDTy >, Allocator< PassInfo::IDTy > > type
PassUPtrTy create_Pass(PassInfo::IDTy ID) const
Definition: PassManager.cpp:63
#define RT_REGISTER_GROUP(var, name, description)
Register a new (toplevel) group.
Definition: rt-timing.hpp:683
std::list< T, Allocator< T > > type
Definition: list.hpp:38
Bold bold
Definition: OStream.cpp:62
PassManager::ScheduleListTy & new_schedule
const_iterator schedule_before_end() const
Definition: PassUsage.hpp:166
const_iterator run_before_begin() const
Definition: PassUsage.hpp:159
alloc::list< PassInfo::IDTy >::type & stack
Stores the interdependencies of a pass.
Definition: PassUsage.hpp:55
Definition: set.cpp:44
const_iterator schedule_before_begin() const
Definition: PassUsage.hpp:165
PassMapTy passes
Stores pass instances so other passes can retrieve their results.
static PassInfoMapTy & registered_passes()
Definition: PassManager.hpp:99
MIIterator i
#define LOG2(STMT)
Definition: logging.hpp:93
ResetColor reset_color
Definition: OStream.cpp:61
static void abort()
Definition: os.hpp:196
#define LOG3(STMT)
Definition: logging.hpp:94
OStream & err()
Definition: OStream.cpp:33
This file contains the real-time timing utilities.
MIIterator e
This file contains the command line option parsing library.
#define LOG(STMT)
Analogous to DEBUG.
Definition: logging.hpp:91
const char * get_Pass_name(PassInfo::IDTy ID)
jmethodID jint const void jint const jvmtiAddrLocationMap * map
Definition: jvmti.h:338
const_iterator destroys_begin() const
Definition: PassUsage.hpp:150
const char * get_name() const
Definition: PassManager.hpp:66
OptionPrefix & xx_root()
Definition: Option.cpp:39
alloc::deque< PassInfo::IDTy >::type & unhandled
const_iterator run_before_end() const
Definition: PassUsage.hpp:160
PIIDSet::const_iterator const_iterator
Definition: PassUsage.hpp:58
#define ABORT_MSG(EXPR_SHORT, EXPR_LONG)
Definition: logging.hpp:133
PriorityQueueTy & ready
Nl nl
Definition: OStream.cpp:56
void runPasses(JITData &JD)
run passes
Definition: PassManager.cpp:91
ScheduleListTy schedule
This is the pass schedule.
Definition: PassManager.hpp:95