CACAO
MachineInstructionSchedulingPass.cpp
Go to the documentation of this file.
1 /* src/vm/jit/compiler2/MachineInstructionSchedulingPass.cpp - MachineInstructionSchedulingPass
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 
33 
35 
38 
39 #include "Target.hpp"
40 
41 #include "toolbox/logging.hpp"
42 
43 #define DEBUG_NAME "compiler2/MachineInstructionSchedulingPass"
44 
45 namespace cacao {
46 namespace jit {
47 namespace compiler2 {
48 
50 #if 0
51  list.clear();
52  map.clear();
53 #endif
54 }
55 
56 
57 namespace {
58 
59 struct UpdatePhiOperand : public std::unary_function<MachinePhiInst*,void> {
61  InstMapTy inst_map;
62  /// constructor
63  UpdatePhiOperand(InstMapTy &inst_map) : inst_map(inst_map) {}
64  /// function operator
65  virtual void operator()(MachinePhiInst* phi) const {
66  PHIInst* phi_inst = phi->get_PHIInst();
67  assert(phi_inst);
68  Instruction::const_op_iterator op = phi_inst->op_begin();
69 
70  for (MachineInstruction::operand_iterator i = phi->begin(),
71  e = phi->end(); i != e; ++i) {
72  Instruction *I = (*op)->to_Instruction();
73  assert(I);
74  InstMapTy::const_iterator it = inst_map.find(I);
75  assert(it != inst_map.end());
76  // set operand
77  i->op = it->second;
78  ++op;
79  }
80  }
81 };
82 
83 // LIST SCHEDULING ADDITIONAL STUFF IN ANONYMOUS NAMESPACE
84 
85 class MyComparator {
86 private:
87  const GlobalSchedule* sched;
88  unsigned users(Instruction *I) const {
89  unsigned users = 0;
90  for (Instruction::UserListTy::const_iterator i = I->user_begin(),
91  e = I->user_end(); i != e; ++i) {
92  Instruction *user = *i;
93  // only instructions in this basic block
94  if ( sched->get(user) == sched->get(I)) {
95  users++;
96  }
97  }
98  return users;
99  }
100 public:
101  MyComparator(const GlobalSchedule* sched) : sched(sched) {}
102  bool operator() (Instruction* lhs, Instruction* rhs) const {
103  if (lhs->get_opcode() != rhs->get_opcode()) {
104  // BeginInst always first!
105  if (lhs->to_BeginInst()) return false;
106  if (rhs->to_BeginInst()) return true;
107  // EndInst always last!
108  if (rhs->to_EndInst()) return false;
109  if (lhs->to_EndInst()) return true;
110  // PHIs right after BeginInst
111  if (lhs->to_PHIInst()) return false;
112  if (rhs->to_PHIInst()) return true;
113  // LOADInst first
114  if (lhs->to_LOADInst()) return false;
115  if (rhs->to_LOADInst()) return true;
116  }
117  // prioritize instruction with fewer users in the current bb
118  unsigned lhs_user = users(lhs);
119  unsigned rhs_user = users(rhs);
120  if (lhs_user == rhs_user) {
121  return InstPtrLess()(rhs,lhs);
122  }
123  return lhs_user > rhs_user;
124  }
125 };
126 
127 typedef alloc::priority_queue<Instruction*,alloc::deque<Instruction*>::type,MyComparator>::type PriorityQueueTy;
128 
129 struct FindLeader2 : public std::unary_function<Value*,void> {
131  GlobalSchedule *sched;
132  Instruction *I;
133  bool &leader;
134  /// constructor
135  FindLeader2(alloc::set<Instruction*>::type &scheduled, GlobalSchedule *sched, Instruction *I, bool &leader)
136  : scheduled(scheduled), sched(sched), I(I), leader(leader) {}
137  /// function call operator
138  void operator()(Value *value) {
139  Instruction *op = value->to_Instruction();
140  assert(op);
141  if (op != I && sched->get(I) == sched->get(op) && scheduled.find(op) == scheduled.end() ) {
142  leader = false;
143  }
144  }
145 };
146 
147 struct FindLeader : public std::unary_function<Instruction*,void> {
149  GlobalSchedule *sched;
150  PriorityQueueTy &ready;
151  BeginInst *BI;
152  /// constructor
153  FindLeader(alloc::set<Instruction*>::type &scheduled, GlobalSchedule *sched, PriorityQueueTy &ready, BeginInst *BI)
154  : scheduled(scheduled), sched(sched), ready(ready), BI(BI) {}
155 
156  /// function call operator
157  void operator()(Instruction* I) {
158  // only instructions in this basic block
159  if ( sched->get(I) != sched->get(BI)) {
160  return;
161  }
162  bool leader = true;
163  // for each operand
164  std::for_each(I->op_begin(), I->op_end(), FindLeader2(scheduled, sched, I, leader));
165  // for each dependency
166  std::for_each(I->dep_begin(), I->dep_end(), FindLeader2(scheduled, sched, I, leader));
167  if (leader) {
168  LOG("leader: " << I << nl);
169  ready.push(I);
170  }
171  }
172 };
173 
174 } // end anonymous namespace
175 
177  BasicBlockSchedule *BS = get_Pass<BasicBlockSchedulingPass>();
178  GlobalSchedule* GS = get_Pass<ScheduleClickPass>();
179 
180 #if !PATTERN_MATCHING
181  IS = shared_ptr<ListSchedulingPass>(new ListSchedulingPass(GS));
182  IS->run(JD);
183 #endif
184 
185 
187 
188  // create machine basic blocks
190  e = BS->bb_end(); i != e ; ++i) {
191  BeginInst *BI = *i;
192  assert(BI);
193  // create MachineBasicBlock
195  map[BI] = MBB;
196  }
197 
198  Backend *BE = JD.get_Backend();
200 
201  // lower instructions
203  e = BS->bb_end(); i != e ; ++i) {
204 
205  BeginInst *BI = *i;
206  MachineBasicBlock *MBB = map[BI];
207  LoweringVisitor LV(BE,MBB,map,inst_map,this);
208 
209 #if !PATTERN_MATCHING
210  LOG2("lowering for BB using list sched " << BI << nl);
212  e = IS->inst_end(BI); i != e; ++i) {
213  Instruction *I = *i;
214  LOG2("lower: " << *I << nl);
215  I->accept(LV, true);
216  }
217 #else
218  LOG2("Lowering with Pattern Matching " << BI << nl);
219  Matcher M(GS, BI, &LV);
220  M.run();
221 #endif
222  // fix predecessors
224  e = BI->pred_end(); i != e; ++i) {
225  BeginInst *pred = (*i)->get_BeginInst();
227  assert(it != map.end());
228  MBB->insert_pred(it->second);
229  }
230 
231  }
232 
233  for (const_iterator i = begin(), e = end(); i != e; ++i) {
234  MachineBasicBlock *MBB = *i;
235  LOG2("MBB: " << *MBB << nl);
236  // fix phi instructions
237  UpdatePhiOperand functor(inst_map);
238  std::for_each(MBB->phi_begin(), MBB->phi_end(), functor);
239  // split basic blocks
240  for (MachineBasicBlock::iterator i = MBB->begin(), e = MBB->end();
241  i != e; ) {
242  MachineInstruction *MI = *i;
243  ++i;
244  if (MI->is_jump() && i != e) {
246  assert(new_MBB);
247  new_MBB->insert_pred(MBB);
248  new_MBB->push_front(new MachineLabelInst());
249  LOG2("new MBB: " << *new_MBB << nl);
250  move_instructions(i,e,*MBB,*new_MBB);
251  break;
252  }
253  }
254  }
255  return true;
256 }
257 
258 // verify
260 
261 #if !PATTERN_MATCHING
262  // call List Scheduling verify first
263  IS->verify();
264 #endif
265 
267  i != e; ++i) {
268  MachineBasicBlock *MBB = *i;
269  if(MBB->size() == 0) {
270  ERROR_MSG("verification failed", "MachineBasicBlock ("
271  << *MBB << ") empty");
272  return false;
273  }
274  MachineInstruction *front = MBB->front();
275  // check for label
276  if(!front->is_label()) {
277  ERROR_MSG("verification failed", "first Instruction ("
278  << *front << ") not a label");
279  return false;
280  }
281  MachineInstruction *back = MBB->back();
282  // check for end
283  if(!back->is_end()) {
284  ERROR_MSG("verification failed", "last Instruction ("
285  << *back << ") not a control flow transfer instruction");
286  return false;
287  }
288 
289  std::size_t num_pred = MBB->pred_size();
290  // check phis
292  i != e; ++i) {
293  MachinePhiInst *phi = *i;
294  if (phi->op_size() != num_pred) {
295  ERROR_MSG("verification failed", "Machine basic block (" << *MBB << ") has "
296  << num_pred << " predecessors but phi node (" << *phi << ") has " << phi->op_size());
297  return false;
298  }
299  }
300 
301  for (MachineBasicBlock::const_iterator i = MBB->begin(), e = MBB->end();
302  i != e ; ++i) {
303  MachineInstruction *MI = *i;
304  // check for block
305  if(!MI->get_block()) {
306  ERROR_MSG("No block", *MI);
307  return false;
308  }
309  }
310  }
311  return true;
312 }
313 
314 // pass usage
319  return PU;
320 }
321 
322 // the address of this variable is used to identify the pass
324 
325 // register pass
326 static PassRegistry<MachineInstructionSchedulingPass> X("MachineInstructionSchedulingPass");
327 
328 // LIST SCHEDULING PART MOVED HERE
329 
331  // reference to the instruction list of the current basic block
332  InstructionListTy &inst_list = map[BI];
333  // set of already scheduled instructions
335  // queue of ready instructions
336  MyComparator comp = MyComparator(sched);
337  PriorityQueueTy ready(comp);
338  // Begin is always the first instruction
339  ready.push(BI);
340  LOG3(Cyan<<"BI: " << BI << reset_color << nl);
342  e = sched->inst_end(BI); i != e; ++i) {
343  Instruction *I = *i;
344  // BI is already in the queue
345  if (I->to_BeginInst() == BI)
346  continue;
347  LOG3("Instruction: " << I << nl);
348  //fill_ready(sched, ready, I);
349  bool leader = true;
350 
351  LOG3("schedule(initial leader): " << I << " #op " << I->op_size() << " #dep " << I->dep_size() << nl);
352  // for each operand
353  std::for_each(I->op_begin(), I->op_end(), FindLeader2(scheduled, sched, I, leader));
354  // for each dependency
355  std::for_each(I->dep_begin(), I->dep_end(), FindLeader2(scheduled, sched, I, leader));
356 
357  if (leader) {
358  LOG("initial leader: " << I << nl);
359  ready.push(I);
360  }
361  }
362 
363  while (!ready.empty()) {
364  Instruction *I = ready.top();
365  ready.pop();
366  if (scheduled.find(I) != scheduled.end()){
367  continue;
368  }
369  inst_list.push_back(I);
370  LOG("insert: " << I << nl);
371  scheduled.insert(I);
372  // for all users
373  std::for_each(I->user_begin(), I->user_end(), FindLeader(scheduled,sched,ready,BI));
374  // for all dependant instruction
375  std::for_each(I->rdep_begin(), I->rdep_end(), FindLeader(scheduled,sched,ready,BI));
376  }
377  #if defined(ENABLE_LOGGING)
378  for(const_inst_iterator i = inst_begin(BI), e = inst_end(BI); i != e ; ++i) {
379  Instruction *I = *i;
380  LOG(I<<nl);
381  }
382  #endif
383  assert( std::distance(inst_begin(BI),inst_end(BI)) == std::distance(sched->inst_begin(BI),sched->inst_end(BI)) );
384 }
385 
387  M = JD.get_Method();
388  for (Method::const_bb_iterator i = M->bb_begin(), e = M->bb_end() ; i != e ; ++i) {
389  BeginInst *BI = *i;
390  LOG("ListScheduling: " << BI << nl);
391  schedule(BI);
392  }
393  #if defined(ENABLE_LOGGING)
394  LOG("Schedule:" << nl);
395  for (Method::const_bb_iterator i = M->bb_begin(), e = M->bb_end() ; i != e ; ++i) {
396  BeginInst *BI = *i;
397  for(const_inst_iterator i = inst_begin(BI), e = inst_end(BI); i != e ; ++i) {
398  Instruction *I = *i;
399  LOG(I<<nl);
400  }
401  }
402  #endif
403  return true;
404 }
405 
407  for (Method::const_iterator i = M->begin(), e = M->end(); i!=e; ++i) {
408  Instruction *I = *i;
409  bool found = false;
410  for (Method::const_bb_iterator i = M->bb_begin(), e = M->bb_end(); i!=e; ++i) {
411  BeginInst *BI = *i;
412  if (std::find(inst_begin(BI),inst_end(BI),I) != inst_end(BI)) {
413  found = true;
414  }
415  }
416  if (!found) {
417  ERROR_MSG("Instruction not Scheduled!","Instruction: " << I);
418  return false;
419  }
420  }
421  return true;
422 }
423 
424 
425 
426 
427 } // end namespace compiler2
428 } // end namespace jit
429 } // end namespace cacao
430 
431 
432 /*
433  * These are local overrides for various environment variables in Emacs.
434  * Please do not remove this and leave it at the end of the file, where
435  * Emacs will automagically detect them.
436  * ---------------------------------------------------------------------
437  * Local variables:
438  * mode: c++
439  * indent-tabs-mode: t
440  * c-basic-offset: 4
441  * tab-width: 4
442  * End:
443  * vim:noexpandtab:sw=4:ts=4:
444  */
alloc::ordered_list< MachineBasicBlock * >::type list
const_inst_iterator inst_end(const BeginInst *BI) const
std::set< Instruction *, std::less< Instruction * >, Allocator< Instruction * > > type
Definition: set.hpp:38
GlobalSchedule TODO: more info.
ordered const_iterator
const_phi_iterator phi_end() const
returns an const iterator to the phi instructions
const_dep_iterator rdep_begin() const
UserListTy::const_iterator user_begin() const
Definition: Value.hpp:72
const_inst_iterator inst_begin(const BeginInst *BI) const
BBListTy::const_iterator const_bb_iterator
Definition: MethodC2.hpp:69
PredecessorListTy::const_iterator const_pred_iterator
const GlobalSchedule * sched
This Instruction mark the start of a basic block.
u2 op
Definition: disass.cpp:129
A basic block of (scheduled) machine instructions.
virtual void accept(InstructionVisitor &v, bool copyOperands)=0
Visitor.
const_dep_iterator dep_begin() const
_Base::const_iterator const_iterator
MBBIterator self_iterator() const
get self iterator
void move_instructions(InputIterator first, InputIterator last, MachineBasicBlock &from, MachineBasicBlock &to)
Move instructions to another basic block.
iterator end()
returns an iterator to the end
ordered iterator
#define ERROR_MSG(EXPR_SHORT, EXPR_LONG)
Definition: logging.hpp:124
iterator begin()
returns an iterator to the beginning
virtual PassUsage & get_PassUsage(PassUsage &PA) const
Set the requirements for the pass.
const_pred_iterator pred_begin() const
std::size_t size() const
returns the number of elements
UserListTy::const_iterator user_end() const
Definition: Value.hpp:73
const_phi_iterator phi_begin() const
returns an const iterator to the phi instructions
OperandListTy::const_iterator const_op_iterator
Definition: Instruction.hpp:80
const_reference front() const
access the first element
const_inst_iterator inst_begin(const BeginInst *BI) const
const_reference back() const
access the last element
iterator begin()
returns an iterator to the beginning
Stores the interdependencies of a pass.
Definition: PassUsage.hpp:55
std::size_t pred_size() const
returns the number of predecessor nodes
void push_front(MachineInstruction *value)
inserts value to the beginning
Instruction super class.
Definition: Instruction.hpp:73
const_dep_iterator rdep_end() const
MIIterator i
MachineInstructionSchedule::iterator insert_after(iterator pos, const MBBBuilder &value)
inserts value after the element pointed to by pos
#define LOG2(STMT)
Definition: logging.hpp:93
ResetColor reset_color
Definition: OStream.cpp:61
InstructionListTy::const_iterator const_iterator
Definition: MethodC2.hpp:67
const_op_iterator op_begin() const
#define LOG3(STMT)
Definition: logging.hpp:94
MIIterator e
#define LOG(STMT)
Analogous to DEBUG.
Definition: logging.hpp:91
Proxy to encode explicit and implicit successors.
#define I(value)
Definition: codegen.c:279
alloc::unordered_set< Instruction * >::type::const_iterator const_inst_iterator
Represents the result of the addition of a certain IR-variable with a certain constant.
Definition: Value.hpp:36
jmethodID jint const void jint const jvmtiAddrLocationMap * map
Definition: jvmti.h:338
const_pred_iterator pred_end() const
const Method & M
BasicBlockListTy::const_iterator const_bb_iterator
const_dep_iterator dep_end() const
alloc::set< Instruction * >::type & scheduled
BasicBlockSchedulingPass TODO: more info.
virtual BeginInst * to_BeginInst()
Definition: Instruction.hpp:89
void insert_pred(MachineBasicBlock *value)
Appends the given element value to the list of predecessors.
const_inst_iterator inst_end(const BeginInst *BI) const
PriorityQueueTy & ready
static PassRegistry< BasicBlockSchedulingPass > X("BasicBlockSchedulingPass")
Nl nl
Definition: OStream.cpp:56
BasicBlockSchedule TODO: more info.
MachineInstructionSchedule::iterator push_back(const MBBBuilder &value)
Appends the given element value to the end of the container.
const_op_iterator op_end() const
void add_requires()
PassName is required.
Definition: PassUsage.hpp:78
InstructionSchedule TODO: more info.
virtual BeginInst * get_BeginInst() const
Get the corresponding BeginInst.