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 
63  Pass *P = initialized_passes[ID];
64  if (!P) {
65  PassInfo *PI = registered_passes()[ID];
66  assert(PI && "Pass not registered");
67  // This should be the only place where a Pass is constructed!
68  P = PI->create_Pass();
69  P->set_PassManager(this);
70  initialized_passes[ID] = P;
71  result_ready[ID] = false;
72  #if ENABLE_RT_TIMING
73  RTTimer &timer = pass_timers[ID];
74  new (&timer) RTTimer(PI->get_name(),PI->get_name(),compiler2_rtgroup());
75  #endif
76  }
77  return P;
78 }
79 
81  // delete all passes
82  for(PassMapTy::iterator i = initialized_passes.begin(), e = initialized_passes.end(); i != e; ++i) {
83  Pass* P = i->second;
84  delete P;
85  }
86 }
87 
89 }
90 
92  LOG("runPasses" << nl);
93  if (option::print_pass_dependencies) {
95  }
98  for(ScheduleListTy::iterator i = schedule.begin(), e = schedule.end(); i != e; ++i) {
99  PassInfo::IDTy id = *i;
100  result_ready[id] = false;
101  #if ENABLE_RT_TIMING
102  PassTimerMap::iterator f = pass_timers.find(id);
103  assert(f != pass_timers.end());
104  RTTimer &timer = f->second;
105  timer.start();
106  #endif
107  Pass* P = get_initialized_Pass(id);
108  LOG("initialize: " << get_Pass_name(id) << nl);
109  P->initialize();
110  LOG("start: " << get_Pass_name(id) << nl);
111  if (!P->run(JD)) {
112  err() << bold << Red << "error" << reset_color << " during pass " << get_Pass_name(id) << nl;
113  os::abort("compiler2: error");
114  }
115  // invalidating results
116  PassUsage PU;
117  PU = P->get_PassUsage(PU);
119  i != e; ++i) {
120  result_ready[*i] = false;
121  LOG("mark invalid" << get_Pass_name(*i) << nl);
122  }
123  #ifndef NDEBUG
124  LOG("verifying: " << get_Pass_name(id) << nl);
125  if (!P->verify()) {
126  err() << bold << Red << "verification error" << reset_color << " during pass " << get_Pass_name(id) << nl;
127  os::abort("compiler2: error");
128  }
129  #endif
130  result_ready[id] = true;
131  LOG("finialize: " << get_Pass_name(id) << nl);
132  P->finalize();
133  #if ENABLE_RT_TIMING
134  timer.stop();
135  #endif
136  }
137  finalizePasses();
138 }
139 
141 }
142 
143 
144 // begin Pass scheduler
145 
146 #undef DEBUG_NAME
147 #define DEBUG_NAME "compiler2/PassManager/Scheduler"
148 namespace {
149 
150 #if defined(ENABLE_LOGGING) || !defined(NDEBUG)
151 // XXX for debugging only, to be removed
152 PassManager* latest = NULL;
153 // XXX for debugging only, to be removed
154 const char* get_Pass_name(PassInfo::IDTy id) {
155  if (!latest) return "PassManager not available";
156  return latest->get_Pass_name(id);
157 }
158 #endif // defined(ENABLE_LOGGING) || !defined(NDEBUG)
159 
160 template <class InputIterator, class ValueType>
161 inline bool contains(InputIterator begin, InputIterator end, const ValueType &val) {
162  return std::find(begin,end,val) != end;
163 }
164 
165 template <class Container, class ValueType>
166 struct ContainsFn {
167  bool operator()(const Container &c, const ValueType &val) {
168  return contains(c.begin(),c.end(),val);
169  }
170 };
171 
172 template <class ValueType>
173 struct ContainsFn<typename alloc::set<ValueType>::type,ValueType> {
174  bool operator()(const typename alloc::set<ValueType>::type &c, const ValueType &val) {
175  return c.find(val) != c.end();
176  }
177 };
178 
179 template <class ValueType>
180 struct ContainsFn<unordered_set<ValueType>,ValueType> {
181  bool operator()(const typename alloc::unordered_set<ValueType>::type &c, const ValueType &val) {
182  return c.find(val) != c.end();
183  }
184 };
185 
186 template <class Container, class ValueType>
187 inline bool contains(const Container &c, const ValueType &val) {
188  return ContainsFn<Container,ValueType>()(c,val);
189 }
190 
191 
192 typedef alloc::unordered_map<PassInfo::IDTy,PassUsage>::type ID2PUTy;
193 typedef alloc::unordered_map<PassInfo::IDTy,alloc::unordered_set<PassInfo::IDTy>::type >::type ID2MapTy;
194 
195 struct Invalidate :
196 public std::unary_function<PassInfo::IDTy,void> {
199  // constructor
201  : reverse_require_map(reverse_require_map), ready(ready) {}
202  // function call operator
203  void operator()(PassInfo::IDTy id) {
204  if (ready.erase(id)) {
205  LOG3(" invalidated: " << get_Pass_name(id) << nl);
206  std::for_each(reverse_require_map[id].begin(),reverse_require_map[id].end(),*this);
207  }
208  }
209 };
210 
211 class PassScheduler {
212 private:
213  alloc::deque<PassInfo::IDTy>::type &unhandled;
215  alloc::list<PassInfo::IDTy>::type &stack;
217  ID2PUTy &pu_map;
218  ID2MapTy &reverse_require_map;
219 public:
220  /// constructor
221  PassScheduler(alloc::deque<PassInfo::IDTy>::type &unhandled, alloc::unordered_set<PassInfo::IDTy>::type &ready,
222  alloc::list<PassInfo::IDTy>::type &stack, PassManager::ScheduleListTy &new_schedule,
223  ID2PUTy &pu_map, ID2MapTy &reverse_require_map)
224  : unhandled(unhandled), ready(ready), stack(stack), new_schedule(new_schedule),
225  pu_map(pu_map), reverse_require_map(reverse_require_map) {}
226  /// call operator
227  void operator()(PassInfo::IDTy id) {
228  if (contains(ready,id)) return;
229  #ifndef NDEBUG
230  if (contains(stack,id)) {
231  ABORT_MSG("PassManager: dependency cycle detected",
232  "Pass " << get_Pass_name(id) << " already stacked for scheduling!");
233  }
234  #endif
235  stack.push_back(id);
236  PassUsage &PU = pu_map[id];
237  LOG3("prescheduled: " << get_Pass_name(id) << nl);
238  bool fixpoint;
239  do {
240  fixpoint = true;
241  // schedule schedule_after
242  for (PassUsage::const_iterator i = PU.schedule_after_begin(), e = PU.schedule_after_end();
243  i != e ; ++i) {
244  LOG3(" schedule_after: " << get_Pass_name(*i) << nl);
245  if (std::find(new_schedule.rbegin(),new_schedule.rend(),*i) == new_schedule.rend()) {
246  operator()(*i);
247  fixpoint = false;
248  }
249  }
250  // schedule requires
251  for (PassUsage::const_iterator i = PU.requires_begin(), e = PU.requires_end();
252  i != e ; ++i) {
253  LOG3(" requires: " << get_Pass_name(*i) << nl);
254  if (ready.find(*i) == ready.end()) {
255  operator()(*i);
256  fixpoint = false;
257  }
258  }
259  } while(!fixpoint);
260 
261  LOG3("scheduled: " << get_Pass_name(id) << nl);
262  // remove all destroyed passes from ready
263  std::for_each(PU.destroys_begin(),PU.destroys_end(),Invalidate(reverse_require_map,ready));
264  // remove all passed depending on modified from ready
265  for (PassUsage::const_iterator i = PU.modifies_begin(), e = PU.modifies_end();
266  i != e ; ++i) {
267  if (ready.find(*i) != ready.end()) {
268  LOG3(" modifies: " << get_Pass_name(*i) << nl);
269  std::for_each(reverse_require_map[*i].begin(),reverse_require_map[*i].end(),
270  Invalidate(reverse_require_map,ready));
271  }
272  }
273  // dummy use
274  unhandled.front();
275  new_schedule.push_back(id);
276  ready.insert(id);
277  stack.pop_back();
278  }
279 };
280 
281 struct RunBefore : public std::unary_function<PassInfo::IDTy,void> {
282  ID2PUTy &pu_map;
284 
285  RunBefore(ID2PUTy &pu_map, PassInfo::IDTy id)
286  : pu_map(pu_map), id(id) {}
287 
288  void operator()(PassInfo::IDTy before) {
289  //pu_map[before].add_schedule_after(id);
290  pu_map[before].add_requires(id);
291  }
292 };
293 
294 struct ScheduleBefore : public std::unary_function<PassInfo::IDTy,void> {
295  ID2PUTy &pu_map;
297 
298  ScheduleBefore(ID2PUTy &pu_map, PassInfo::IDTy id)
299  : pu_map(pu_map), id(id) {}
300 
301  void operator()(PassInfo::IDTy before) {
302  pu_map[before].add_schedule_after(id);
303  }
304 };
305 
306 struct AddReverseRequire : public std::unary_function<PassInfo::IDTy,void> {
307  ID2MapTy &map;
309 
310  AddReverseRequire(ID2MapTy &map, PassInfo::IDTy id)
311  : map(map), id(id) {}
312 
313  void operator()(PassInfo::IDTy required_by) {
314  map[required_by].insert(id);
315  }
316 };
317 
318 struct ReverseRequire :
319 public std::unary_function<ID2PUTy::value_type,void> {
320  ID2MapTy &map;
321  // constructor
322  ReverseRequire(ID2MapTy &map) : map(map) {}
323  // function call operator
324  void operator()(argument_type pair) {
325  std::for_each(pair.second.requires_begin(), pair.second.requires_end(),AddReverseRequire(map,pair.first));
326  }
327 };
328 
329 } // end anonymous namespace
330 
332 #if defined(ENABLE_LOGGING) || !defined(NDEBUG)
333  // XXX for debugging only, to be removed
334  latest = this;
335 #endif
336 
341  ID2PUTy pu_map;
342  ID2MapTy reverse_require_map;
343 
345  i != e; ++i) {
346  PassInfo::IDTy id = i->first;
347  Pass *pass = get_initialized_Pass(id);
348  PassUsage &PA = pu_map[id];
349  pass->get_PassUsage(PA);
350  // add run before
351  std::for_each(PA.run_before_begin(),PA.run_before_end(),RunBefore(pu_map,id));
352  // add schedule before
353  std::for_each(PA.schedule_before_begin(),PA.schedule_before_end(),ScheduleBefore(pu_map,id));
354  }
355  // fill reverser required map
356  std::for_each(pu_map.begin(),pu_map.end(),ReverseRequire(reverse_require_map));
357  //
358  std::copy(schedule.begin(), schedule.end(), std::back_inserter(unhandled));
359 
360  PassScheduler scheduler(unhandled,ready,stack,new_schedule,pu_map,reverse_require_map);
361  while (!unhandled.empty()) {
362  PassInfo::IDTy id = unhandled.front();
363  unhandled.pop_front();
364  // schedule
365  scheduler(id);
366  assert(stack.empty());
367  }
368 
369  if (DEBUG_COND_N(2)) {
370  LOG2("old Schedule:" << nl);
371  for (ScheduleListTy::const_iterator i = schedule.begin(),
372  e = schedule.end(); i != e ; ++i) {
373  LOG2(" " << get_Pass_name(*i) << " id: " << *i << nl);
374  }
375  LOG2("new Schedule:" << nl);
376  for (ScheduleListTy::const_iterator i = new_schedule.begin(),
377  e = new_schedule.end(); i != e ; ++i) {
378  LOG2(" " << get_Pass_name(*i) << " id: " << *i << nl);
379  }
380  }
382 }
383 } // end namespace cacao
384 } // end namespace jit
385 } // end namespace compiler2
386 
387 /*
388  * These are local overrides for various environment variables in Emacs.
389  * Please do not remove this and leave it at the end of the file, where
390  * Emacs will automagically detect them.
391  * ---------------------------------------------------------------------
392  * Local variables:
393  * mode: c++
394  * indent-tabs-mode: t
395  * c-basic-offset: 4
396  * tab-width: 4
397  * End:
398  * vim:noexpandtab:sw=4:ts=4:
399  */
void finalizePasses()
run pass finalizers
ID2MapTy & reverse_require_map
Pass superclass All compiler passes should inheritate this class.
Definition: Pass.hpp:48
void set_PassManager(PassManager *PM)
Definition: Pass.hpp:55
virtual PassUsage & get_PassUsage(PassUsage &PU) const
Set the requirements for the pass.
Definition: Pass.hpp:87
ID2PUTy & pu_map
PassMapTy initialized_passes
This stores the initialized passes.
Definition: PassManager.hpp:87
void print_PassDependencyGraph(PassManager &PM)
const_iterator destroys_end() const
Definition: PassUsage.hpp:151
std::deque< T, Allocator< T > > type
Definition: deque.hpp:38
_Base::const_iterator const_iterator
virtual void finalize()
Finalize the Pass.
Definition: Pass.hpp:105
PassInfo::IDTy id
#define DEBUG_COND_N(VERBOSE)
Definition: Debug.hpp:112
Pass * get_initialized_Pass(PassInfo::IDTy ID)
Definition: PassManager.cpp:62
#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
void initializePasses()
run pass initializers
Definition: PassManager.cpp:88
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
static PassInfoMapTy & registered_passes()
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
virtual bool run(JITData &JD)=0
Run the Pass.
This file contains the real-time timing utilities.
MIIterator e
virtual bool verify() const
Verify the Result.
Definition: Pass.hpp:121
alloc::vector< PassInfo::IDTy >::type ScheduleListTy
Definition: PassManager.hpp:78
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
void runPasses(JITData &JD)
run passes
Definition: PassManager.cpp:91
const_iterator destroys_begin() const
Definition: PassUsage.hpp:150
const char * get_name() const
Definition: PassManager.hpp:61
OptionPrefix & xx_root()
Definition: Option.cpp:39
alloc::deque< PassInfo::IDTy >::type & unhandled
const_iterator run_before_end() const
Definition: PassUsage.hpp:160
cacao::unordered_set< PassInfo::IDTy, cacao::hash< PassInfo::IDTy >, std::equal_to< PassInfo::IDTy >, Allocator< PassInfo::IDTy > > type
PIIDSet::const_iterator const_iterator
Definition: PassUsage.hpp:58
ResultReadyMapTy result_ready
Map of ready results.
#define ABORT_MSG(EXPR_SHORT, EXPR_LONG)
Definition: logging.hpp:133
PriorityQueueTy & ready
Nl nl
Definition: OStream.cpp:56
virtual void initialize()
Initialize the Pass.
Definition: Pass.hpp:98
_Base::iterator iterator
ScheduleListTy schedule
This variable contains a schedule of the passes.
Definition: PassManager.hpp:92