CACAO
GlobalValueNumberingPass.cpp
Go to the documentation of this file.
1 /* src/vm/jit/compiler2/GlobalValueNumberingPass.cpp - GlobalValueNumberingPass
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 
34 #include "toolbox/logging.hpp"
35 
36 // define name for debugging (see logging.hpp)
37 #define DEBUG_NAME "compiler2/GlobalValueNumberingPass"
38 
39 STAT_DECLARE_GROUP(compiler2_stat)
40 STAT_REGISTER_SUBGROUP(compiler2_globalvaluenumberingpass_stat,
41  "globalvaluenumberingpass","globalvaluenumberingpass",compiler2_stat)
42 STAT_REGISTER_GROUP_VAR(std::size_t,num_total_const,0,"# CONSTInsts",
43  "total number of CONSTInst nodes",compiler2_globalvaluenumberingpass_stat)
44 STAT_REGISTER_GROUP_VAR(std::size_t,num_total_arith,0,"# arithmetical nodes",
45  "total number of arithmetical nodes",compiler2_globalvaluenumberingpass_stat)
46 STAT_REGISTER_GROUP_VAR(std::size_t,num_total_phi,0,"# PHIInsts",
47  "total number of PHIInst nodes",compiler2_globalvaluenumberingpass_stat)
48 STAT_REGISTER_GROUP_VAR(std::size_t,num_total_arraybc,0,"# ARRAYBOUNDSCHECKInsts",
49  "total number of ARRAYBOUNDSCHECKInst nodes",compiler2_globalvaluenumberingpass_stat)
50 STAT_REGISTER_GROUP_VAR(std::size_t,num_redundant_const,0,"# redundant CONSTInsts",
51  "number of redundant CONSTInst nodes",compiler2_globalvaluenumberingpass_stat)
52 STAT_REGISTER_GROUP_VAR(std::size_t,num_redundant_arith,0,"# redundant arithmetical nodes",
53  "number of redundant arithmetical nodes",compiler2_globalvaluenumberingpass_stat)
54 STAT_REGISTER_GROUP_VAR(std::size_t,num_redundant_phi,0,"# redundant PHIInsts",
55  "number of redundant PHIInst nodes",compiler2_globalvaluenumberingpass_stat)
56 STAT_REGISTER_GROUP_VAR(std::size_t,num_redundant_arraybc,0,"# redundant ARRAYBOUNDSCHECKInsts",
57  "number of redundant ARRAYBOUNDSCHECKInst nodes",compiler2_globalvaluenumberingpass_stat)
58 
59 #define STAT_NODE_COUNT_HELPER(INST, CNT, INFIX) \
60  if ((INST)->get_opcode() == Instruction::CONSTInstID) { \
61  STATISTICS(num_##INFIX##_const += (CNT)); \
62  } else if ((INST)->is_arithmetic()) { \
63  STATISTICS(num_##INFIX##_arith += (CNT)); \
64  } else if ((INST)->get_opcode() == Instruction::PHIInstID) { \
65  STATISTICS(num_##INFIX##_phi += (CNT)); \
66  } else if ((INST)->get_opcode() == Instruction::ARRAYBOUNDSCHECKInstID) { \
67  STATISTICS(num_##INFIX##_arraybc += (CNT)); \
68  }
69 #define STAT_TOTAL_NODES(INST) STAT_NODE_COUNT_HELPER(INST, 1, total)
70 #define STAT_REDUNDANT_NODES(INST, CNT) STAT_NODE_COUNT_HELPER(INST, CNT, redundant)
71 
72 namespace cacao {
73 namespace jit {
74 namespace compiler2 {
75 
77 
78  OpcodeBlockMapTy opcodeToBlock;
79  LongBlockMapTy longToBlock;
80  IntBlockMapTy intToBlock;
81  FloatBlockMapTy floatToBlock;
82  DoubleBlockMapTy doubleToBlock;
83  BBBlockMapTy bbToBlock;
84 
85  for (Method::const_iterator i = begin, e = end; i != e; ++i) {
86  Instruction *I = *i;
87  BlockTy *block = (BlockTy*) 0;
88 
90 
91  if (I->has_side_effects()
92  || I->get_opcode() == Instruction::LOADInstID
93  || I->get_opcode() == Instruction::ALOADInstID) {
94  // instructions which change the global state or depend on it
95  // will be in a separate block each, because they are congruent
96  // only with themselves
97 
98  block = create_block();
99  } else if (I->get_opcode() == Instruction::CONSTInstID) {
100  CONSTInst *constInst = I->to_CONSTInst();
101  // for each constant an initial block will be created,
102  // holding all the nodes of the same constant type that have
103  // equal values.
104 
105  switch (constInst->get_type()) {
106  case Type::IntTypeID:
107  block = get_or_create_block(intToBlock,
108  constInst->get_Int());
109  break;
110  case Type::LongTypeID:
111  block = get_or_create_block(longToBlock,
112  constInst->get_Long());
113  break;
114  case Type::FloatTypeID:
115  block = get_or_create_block(floatToBlock,
116  constInst->get_Float());
117  break;
118  case Type::DoubleTypeID:
119  block = get_or_create_block(doubleToBlock,
120  constInst->get_Double());
121 
122  break;
123  default:
124  assert(0 && "illegal type");
125  }
126  } else if (I->get_opcode() == Instruction::PHIInstID) {
127  // all PHIInsts which belong to the same basic block
128  // will be pooled into a common initial block
129  // TODO: generally this should hold for other instructions
130  // that are floating
131 
132  PHIInst *phiInst = I->to_PHIInst();
133  assert(phiInst);
134  BeginInst *bb = phiInst->get_BeginInst();
135  block = get_or_create_block(bbToBlock, bb);
136  } else if (I->get_opcode() != Instruction::BeginInstID
137  && !I->to_EndInst()) {
138  // all other instructions which are no control flow
139  // instructions will be pooled into a common block
140  // per opcode
141 
142  block = get_or_create_block(opcodeToBlock,
143  I->get_opcode());
144  }
145 
146  if (block) {
147  add_to_block(block, I);
148  }
149  }
150 }
151 
152 /**
153  * creates and returns a new block and does some setup work needed
154  * for the further execution of the partitioning algorithm
155  */
158  BlockTy *block = new BlockTy();
159  partition.push_back(block);
161  return block;
162 }
163 
165  block->insert(inst);
166  inst2BlockMap[inst] = block;
167 }
168 
170  BlockTy::const_iterator i = block->begin();
171  Instruction *I = *i;
172  return I->op_size();
173 }
174 
177  std::size_t max = 0;
178  for (Method::const_iterator i = begin, e = end; i != e; i++) {
179  Instruction *I = *i;
180  if (I->op_size() > max) {
181  max = I->op_size();
182  }
183  }
184  return max;
185 }
186 
188  // TODO: clear all the containers
189  for (PartitionTy::const_iterator i = partition.begin(),
190  e = partition.end(); i != e; i++) {
191  BlockTy *block = *i;
192 
193  for (int operandIndex = 0; operandIndex < max_arity; operandIndex++) {
194  // create new work list pair
195  WorkListPairTy *pair = new WorkListPairTy();
196  pair->first = block;
197  pair->second = operandIndex;
198  workList.push_back(pair);
199 
200  // mark work list pair
201  set_in_worklist(block, operandIndex, true);
202  }
203  }
204 }
205 
208  OperandIndex2UsersTy *inverseVector = operandInverseMap[inst];
209  if (!inverseVector) {
210  inverseVector = new OperandIndex2UsersTy();
211  operandInverseMap[inst] = inverseVector;
212  for (int i = 0; i < max_arity; i++) {
213  InstructionListTy *users = new InstructionListTy();
214  inverseVector->push_back(users);
215  }
216  }
217  return (*inverseVector)[op_index];
218 }
219 
221  for (Method::const_iterator i = begin, e = end; i != e; ++i) {
222  Instruction *I = *i;
223  int op_index = 0;
225  oe = I->op_end(); oi != oe; oi++) {
226  Instruction *Op = (*oi)->to_Instruction();
227  assert(Op);
228  InstructionListTy *users = get_users(Op, op_index);
229  users->push_back(I);
230  op_index++;
231  }
232  }
233 }
234 
236  std::vector<bool> *flags = inWorkList[block];
237  if (!flags) {
238  flags = new std::vector<bool>(max_arity);
239  inWorkList[block] = flags;
240  }
241  return flags;
242 }
243 
245  std::vector<bool> *flags = get_worklist_flags(block);
246  (*flags)[index] = flag;
247 }
248 
250  std::vector<bool> *flags = get_worklist_flags(block);
251  return (*flags)[index];
252 }
253 
255  // create new work list pair
256  WorkListPairTy *pair = new WorkListPairTy();
257  pair->first = block;
258  pair->second = index;
259  workList.push_back(pair);
260 
261  // mark work list pair
262  set_in_worklist(block, index, true);
263 }
264 
266  WorkListPairTy *pair = workList.front();
267  workList.pop_front();
268  set_in_worklist(pair->first, pair->second, false);
269  return pair;
270 }
271 
275 }
276 
279  return inst2BlockMap[inst];
280 }
281 
283  BlockTy *new_block = create_block();
284 
285  assert(block->size() > instructions->size());
286 
287  // remove the given instructions from the given block and move them
288  // to the new one
289  for (TouchedInstListTy::const_iterator i = instructions->begin(),
290  e = instructions->end(); i != e; i++) {
291  Instruction *I = *i;
292  block->erase(I);
293  add_to_block(new_block, I);
294  }
295 
296  for (int operandIndex = 0; operandIndex < max_arity; operandIndex++) {
297  if (!is_in_worklist(block, operandIndex)
298  && block->size() <= new_block->size()) {
299  add_to_worklist(block, operandIndex);
300  } else {
301  add_to_worklist(new_block, operandIndex);
302  }
303  }
304 }
305 
307  for (PartitionTy::const_iterator i = partition.begin(),
308  e = partition.end(); i != e; i++) {
309  BlockTy *block = *i;
310  if (block->size() > 1) {
312  }
313  }
314 }
315 
317  BlockTy::iterator i = block->begin();
318  Instruction *inst = *i;
319  i++;
320 
321  // the first node in the block will be used to replace all the others in
322  // the block, the rest of them (i.e. block->size() - 1) is redundant
323  STAT_REDUNDANT_NODES(inst, block->size() - 1);
324 
325  for (BlockTy::iterator e = block->end(); i != e; i++) {
326  Instruction *replacable = *i;
327  replacable->replace_value(inst);
328 
330  // TODO: consider scheduling dependencies of other instruction types
331  // as well (but at the time of implementation the only instruction
332  // type with scheduling dependencies are array bounds check nodes)
333 
336  while ((i = replacable->rdep_begin()) != e) {
337  Instruction *dependent = *i;
338  dependent->append_dep(inst);
339  dependent->remove_dep(replacable);
340  }
341  }
342  }
343 }
344 
346  #if ENABLE_LOGGING
347  for (TouchedInstListTy::const_iterator i = instructions->begin(),
348  e = instructions->end(); i != e; i++) {
349  LOG(*i << nl);
350  }
351  #endif
352 }
353 
355  #if ENABLE_LOGGING
356  for (BlockTy::const_iterator i = block->begin(),
357  e = block->end(); i != e; i++) {
358  Instruction *I = *i;
359  LOG(I << nl);
360  }
361  #endif
362 }
363 
365  #if ENABLE_LOGGING
366  for (PartitionTy::const_iterator i = partition.begin(),
367  e = partition.end(); i != e; i++) {
368  LOG("=============================================================" << nl);
369  LOG("Block:" << nl);
370  BlockTy *block = *i;
371  print_block(block);
372  }
373  #endif
374 }
375 
376 template <typename T>
377 void delete_all(T *lst) {
378  while (!lst->empty()) {
379  delete lst->back();
380  lst->pop_back();
381  }
382 }
383 
384 template <typename T1, typename T2, typename Iterator>
385 void delete_in_range(unordered_map<T1,T2> *map, Iterator begin, Iterator end) {
386  Iterator i = begin;
387  while (i != end) {
388  delete i->second;
389  map->erase(i++);
390  }
391 }
392 
393 template <typename T1, typename T2>
394 void delete_all(unordered_map<T1,T2> *map) {
395  delete_in_range(map, map->begin(), map->end());
396 }
397 
401  while (i != e) {
402  OperandIndex2UsersTy *opUsers = i->second;
403  delete_all(opUsers);
404  delete opUsers;
405  operandInverseMap.erase(i++);
406  }
407 }
408 
410  Method *M = JD.get_Method();
411 
412  max_arity = compute_max_arity(M->begin(), M->end());
413  init_partition(M->begin(), M->end());
415  init_operand_inverse(M->begin(), M->end());
416 
417  LOG("BEFORE PARTITIONING" << nl);
418  print_blocks();
419 
420  while (!workList.empty()) {
422  BlockTy *block = workListPair->first;
423  int operandIndex = workListPair->second;
424  delete workListPair;
425 
426  std::list<BlockTy*> touched;
427 
428  for (BlockTy::const_iterator i = block->begin(),
429  e = block->end(); i != e; i++) {
430  Instruction *I = *i;
431  InstructionListTy *usersForIndex = get_users(I, operandIndex);
432 
433  for (InstructionListTy::const_iterator ui = usersForIndex->begin(),
434  ue = usersForIndex->end(); ui != ue; ui++) {
435  Instruction *user = *ui;
436  BlockTy *userBlock = get_block(user);
437 
438  // the user's block can be 0 if it is an end inst
439  if (userBlock) {
440  touched.push_back(userBlock);
441  TouchedInstListTy *touchedInstructions =
442  get_touched_instructions(userBlock);
443  touchedInstructions->insert(user);
444  }
445  }
446  }
447 
448  // we have to look at every block that contains instructions
449  // whose operand at index operandIndex is in the current block
450  for (std::list<BlockTy*>::const_iterator i = touched.begin(),
451  e = touched.end(); i != e; i++) {
452  BlockTy *touchedBlock = *i;
453  TouchedInstListTy *touchedInstructions = get_touched_instructions(touchedBlock);
454 
455  if (touchedInstructions->size() > 0
456  && touchedBlock->size() != touchedInstructions->size()) {
457  LOG("split block (" << touchedBlock->size() << ", " << touchedInstructions->size() << ")" << nl);
458  print_block(touchedBlock);
459  LOG("remove" << nl);
460  print_instructions(touchedInstructions);
461  split(touchedBlock, touchedInstructions);
462  }
463  touchedInstructions->clear();
464  }
465  }
466 
467  LOG(nl << "AFTER PARTITIONING" << nl);
468  print_blocks();
470 
476 
477  return true;
478 }
479 
480 // pass usage
484  return PU;
485 }
486 
487 // the address of this variable is used to identify the pass
489 
490 // register pass
491 static PassRegistry<GlobalValueNumberingPass> X("GlobalValueNumberingPass");
492 
493 } // end namespace compiler2
494 } // end namespace jit
495 } // end namespace cacao
496 
497 
498 /*
499  * These are local overrides for various environment variables in Emacs.
500  * Please do not remove this and leave it at the end of the file, where
501  * Emacs will automagically detect them.
502  * ---------------------------------------------------------------------
503  * Local variables:
504  * mode: c++
505  * indent-tabs-mode: t
506  * c-basic-offset: 4
507  * tab-width: 4
508  * End:
509  * vim:noexpandtab:sw=4:ts=4:
510  */
std::size_t index
void delete_all(T *lst)
#define STATISTICS(x)
Wrapper for statistics only code.
Definition: statistics.hpp:975
const_dep_iterator rdep_begin() const
#define STAT_REGISTER_SUBGROUP(var, name, description, group)
Register a statistics group and add it to a group.
Definition: statistics.hpp:974
#define max(a, b)
Definition: lsra.hpp:80
_Base::const_iterator const_iterator
InstructionListTy * get_users(Instruction *inst, int op_index)
OperandListTy::const_iterator const_op_iterator
Definition: Instruction.hpp:80
void add_schedule_before()
Schedule before PassName.
Definition: PassUsage.hpp:127
InstID get_opcode() const
return the opcode of the instruction
BeginInst *& block
void replace_value(Value *v)
Replace this Value this the new one in all users.
Definition: Value.cpp:55
unordered_map< Instruction::InstID, BlockTy *, hash< int > > OpcodeBlockMapTy
these types are needed for the creation of the inital blocks
void delete_in_range(unordered_map< T1, T2 > *map, Iterator begin, Iterator end)
void set_in_worklist(BlockTy *block, int index, bool flag)
#define STAT_REDUNDANT_NODES(INST, CNT)
std::vector< bool > * get_worklist_flags(BlockTy *block)
Stores the interdependencies of a pass.
Definition: PassUsage.hpp:55
void init_operand_inverse(Method::const_iterator begin, Method::const_iterator end)
#define STAT_REGISTER_GROUP_VAR(type, var, init, name, description, group)
Register an statistics variable and add it to a group.
Definition: statistics.hpp:967
virtual Instruction * to_Instruction()
Instruction super class.
Definition: Instruction.hpp:73
void split(BlockTy *block, TouchedInstListTy *instructions)
const_dep_iterator rdep_end() const
void add_to_worklist(BlockTy *block, int operandIndex)
MIIterator i
unordered_map< BeginInst *, BlockTy * > BBBlockMapTy
DepListTy::const_iterator const_dep_iterator
Definition: Instruction.hpp:81
InstructionListTy::const_iterator const_iterator
Definition: MethodC2.hpp:67
const_iterator end() const
Definition: MethodC2.hpp:141
const_op_iterator op_begin() const
std::vector< InstructionListTy * > OperandIndex2UsersTy
MIIterator e
#define LOG(STMT)
Analogous to DEBUG.
Definition: logging.hpp:91
_Base::iterator iterator
#define I(value)
Definition: codegen.c:279
static int compute_max_arity(Method::const_iterator begin, Method::const_iterator end)
jmethodID jint const void jint const jvmtiAddrLocationMap * map
Definition: jvmti.h:338
#define STAT_TOTAL_NODES(INST)
#define STAT_DECLARE_GROUP(var)
Declare an external group (or subgroup).
Definition: statistics.hpp:970
const Method & M
const_iterator begin() const
Definition: MethodC2.hpp:137
TouchedInstListTy * get_touched_instructions(BlockTy *block)
void init_partition(Method::const_iterator begin, Method::const_iterator end)
void add_to_block(BlockTy *block, Instruction *inst)
virtual PassUsage & get_PassUsage(PassUsage &PU) const
Set the requirements for the pass.
static PassRegistry< BasicBlockSchedulingPass > X("BasicBlockSchedulingPass")
Nl nl
Definition: OStream.cpp:56
BlockTy * create_block()
creates and returns a new block and does some setup work needed for the further execution of the part...
void print_instructions(TouchedInstListTy *instructions)
const_op_iterator op_end() const
void add_requires()
PassName is required.
Definition: PassUsage.hpp:78
#define STAT_NODE_COUNT_HELPER(INST, CNT, INFIX)