CACAO
ConstantPropagationPass.cpp
Go to the documentation of this file.
1 /* src/vm/jit/compiler2/ConstantPropagationPass.cpp - ConstantPropagationPass
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 
35 
36 #define DEBUG_NAME "compiler2/ConstantPropagationPass"
37 
38 STAT_DECLARE_GROUP(compiler2_stat)
39 STAT_REGISTER_SUBGROUP(compiler2_constantpropagationpass_stat,
40  "constantpropagationpass","constantpropagationpass",compiler2_stat)
41 STAT_REGISTER_GROUP_VAR(std::size_t,num_constant_expr,0,"# evaluated expressions",
42  "number of nodes which could be folded",compiler2_constantpropagationpass_stat)
43 STAT_REGISTER_GROUP_VAR(std::size_t,num_constant_phis,0,"# evaluated phi functions",
44  "number of PHIInsts which could be replaced",compiler2_constantpropagationpass_stat)
45 
46 
47 namespace cacao {
48 namespace jit {
49 namespace compiler2 {
50 
51 /// BinaryOperation function object class
52 template <typename T, Instruction::InstID ID>
53 struct BinaryOperation : public std::binary_function<T,T,T> {
54  T operator()(const T &lhs, const T &rhs) const ;
55 };
56 
57 /// Template specialization for ADDInstID
58 template <typename T>
59 struct BinaryOperation<T, Instruction::ADDInstID> :
60  public std::binary_function<T,T,T> {
61  T operator()(const T &lhs, const T &rhs) const {
62  return lhs + rhs;
63  }
64 };
65 
66 /// Template specialization for SUBInstID
67 template <typename T>
68 struct BinaryOperation<T, Instruction::SUBInstID> :
69  public std::binary_function<T,T,T> {
70  T operator()(const T &lhs, const T &rhs) const {
71  return lhs - rhs;
72  }
73 };
74 
75 /// Template specialization for MULInstID
76 template <typename T>
77 struct BinaryOperation<T, Instruction::MULInstID> :
78  public std::binary_function<T,T,T> {
79  T operator()(const T &lhs, const T &rhs) const {
80  return lhs * rhs;
81  }
82 };
83 
84 /// Template specialization for DIVInstID
85 template <typename T>
86 struct BinaryOperation<T, Instruction::DIVInstID> :
87  public std::binary_function<T,T,T> {
88  T operator()(const T &lhs, const T &rhs) const {
89  return lhs / rhs;
90  }
91 };
92 
93 /// Template specialization for ANDInstID
94 template <typename T>
95 struct BinaryOperation<T, Instruction::ANDInstID> :
96  public std::binary_function<T,T,T> {
97  T operator()(const T &lhs, const T &rhs) const {
98  return lhs & rhs;
99  }
100 };
101 
102 /// function wrapper for BinaryOperation
103 template <typename T>
104 inline T binaryOperate(Instruction::InstID ID, const T &lhs, const T &rhs) {
105  switch (ID) {
114  default:
115  assert(0 && "not implemented");
116  break;
117  }
118  // unreachable - dummy result
119  return lhs;
120 }
121 
122 CONSTInst *foldBinaryInst(BinaryInst *inst) {
123  CONSTInst *op1 = inst->get_operand(0)->to_Instruction()->to_CONSTInst();
124  CONSTInst *op2 = inst->get_operand(1)->to_Instruction()->to_CONSTInst();
125  assert(op1 && op2);
126 
127  switch (inst->get_type()) {
128  case Type::IntTypeID:
129  return new CONSTInst(binaryOperate(inst->get_opcode(),
130  op1->get_Int(), op2->get_Int()), Type::IntType());
131  case Type::LongTypeID:
132  return new CONSTInst(binaryOperate(inst->get_opcode(),
133  op1->get_Long(), op2->get_Long()), Type::LongType());
134  case Type::FloatTypeID:
135  return new CONSTInst(binaryOperate(inst->get_opcode(),
136  op1->get_Float(), op2->get_Float()), Type::FloatType());
137  case Type::DoubleTypeID:
138  return new CONSTInst(binaryOperate(inst->get_opcode(),
139  op1->get_Double(), op2->get_Double()), Type::DoubleType());
140  default:
141  assert(0);
142  return 0;
143  }
144 }
145 
146 /// UnaryOperation function object class
147 template <typename T, Instruction::InstID ID>
148 struct UnaryOperation :public std::unary_function<T,T> {
149  T operator()(const T &op) const;
150 };
151 
152 /// Template specialization for NEGInstID
153 template <typename T>
154 struct UnaryOperation<T, Instruction::NEGInstID> :
155  public std::unary_function<T,T> {
156  T operator()(const T &op) const {
157  return -op;
158  }
159 };
160 
161 /// function wrapper for UnaryOperation
162 template <typename T>
163 inline T unaryOperate(Instruction::InstID ID, const T &op) {
164  switch (ID) {
167  default:
168  assert(0 && "not implemented");
169  break;
170  }
171  // unreachable - dummy result
172  return op;
173 }
174 
175 
176 CONSTInst *foldUnaryInst(UnaryInst *inst) {
177  CONSTInst *op = inst->get_operand(0)->to_Instruction()->to_CONSTInst();
178  assert(op);
179  assert(inst->get_type() == op->get_type());
180 
181  switch (inst->get_type()) {
182  case Type::IntTypeID:
183  return new CONSTInst(unaryOperate(inst->get_opcode(),
184  op->get_Int()), Type::IntType());
185  case Type::LongTypeID:
186  return new CONSTInst(unaryOperate(inst->get_opcode(),
187  op->get_Long()), Type::LongType());
188  case Type::FloatTypeID:
189  return new CONSTInst(unaryOperate(inst->get_opcode(),
190  op->get_Float()), Type::FloatType());
191  case Type::DoubleTypeID:
192  return new CONSTInst(unaryOperate(inst->get_opcode(),
193  op->get_Double()), Type::DoubleType());
194  default:
195  assert(0);
196  return 0;
197  }
198 }
199 
200 template <typename T>
201 CONSTInst *castOperate(CASTInst *inst, const T &op) {
202  switch (inst->get_type()) {
203  case Type::IntTypeID:
204  return new CONSTInst((int32_t) op, Type::IntType());
205  case Type::LongTypeID:
206  return new CONSTInst((int64_t) op, Type::LongType());
207  case Type::FloatTypeID:
208  return new CONSTInst((float) op, Type::FloatType());
209  case Type::DoubleTypeID:
210  return new CONSTInst((double) op, Type::DoubleType());
211  default:
212  assert(0);
213  return 0;
214  }
215 }
216 
217 CONSTInst *foldCASTInst(CASTInst *inst) {
218  CONSTInst *op = inst->get_operand(0)->to_Instruction()->to_CONSTInst();
219  assert(op);
220 
221  switch (op->get_type()) {
222  case Type::IntTypeID:
223  return castOperate(inst, op->get_Int());
224  case Type::LongTypeID:
225  return castOperate(inst, op->get_Long());
226  case Type::FloatTypeID:
227  return castOperate(inst, op->get_Float());
228  case Type::DoubleTypeID:
229  return castOperate(inst, op->get_Double());
230  default:
231  assert(0);
232  return 0;
233  }
234 }
235 
236 CONSTInst *foldInstruction(Instruction *inst) {
237  // TODO: distinguish arithmetical and bitwise operations
238  if (inst->get_opcode() == Instruction::CASTInstID) {
239  return foldCASTInst(inst->to_CASTInst());
240  } else if (inst->to_UnaryInst()) {
241  return foldUnaryInst(inst->to_UnaryInst());
242  } else if (inst->to_BinaryInst()) {
243  return foldBinaryInst(inst->to_BinaryInst());
244  }
245 
246  return 0;
247 }
248 
251  e = inst->user_end(); i != e; i++) {
252  Instruction *user = *i;
253  constantOperands[user]++;
254  if (!inWorkList[user]) {
255  workList.push_back(user);
256  inWorkList[user] = true;
257  }
258  }
259 }
260 
262  CONSTInst *c, Method *M) {
263  assert(inst);
264  assert(c);
265 
266  LOG("replace " << inst << " by " << c << nl);
267  inst->replace_value(c);
268  propagate(c);
269 }
270 
271 bool has_only_constant_operands(Instruction *inst) {
272  assert(inst->op_size() > 0);
273  CONSTInst *firstOp = inst->get_operand(0)->to_Instruction()->to_CONSTInst();
274  for (Instruction::const_op_iterator i = inst->op_begin(),
275  e = inst->op_end(); i != e; i++) {
276  CONSTInst *op = (*i)->to_Instruction()->to_CONSTInst();
277  bool equal;
278 
279  switch (inst->get_type()) {
280  case Type::IntTypeID:
281  equal = firstOp->get_Int() == op->get_Int();
282  break;
283  case Type::LongTypeID:
284  equal = firstOp->get_Long() == op->get_Long();
285  break;
286  case Type::FloatTypeID:
287  equal = firstOp->get_Float() == op->get_Float();
288  break;
289  case Type::DoubleTypeID:
290  equal = firstOp->get_Double() == op->get_Double();
291  break;
292  default:
293  assert(0);
294  return false;
295  }
296 
297  if (!equal)
298  return false;
299  }
300  return true;
301 }
302 
303 bool can_be_statically_evaluated(Instruction *inst) {
304  return inst->is_arithmetic()
305  || inst->get_opcode() == Instruction::CASTInstID;
306 }
307 
309  Method *M = JD.get_Method();
310 
311  workList.clear();
312  workList.insert(workList.begin(), M->begin(), M->end());
313 
314  inWorkList.clear();
315  for (Method::const_iterator i = workList.begin(), e = workList.end();
316  i != e; i++) {
317  inWorkList[*i] = true;
318  }
319 
320  constantOperands.clear();
321 
322  // The actual optimization steps are done within this loop.
323  while (!workList.empty()) {
324  Instruction *I = workList.front();
325  workList.pop_front();
326  inWorkList[I] = false;
327 
328  if (constantOperands[I] == I->op_size()) {
329  if (I->get_opcode() == Instruction::CONSTInstID) {
330  propagate(I);
331  } else if (can_be_statically_evaluated(I)) {
332  CONSTInst *foldedInst = foldInstruction(I);
333  if (foldedInst) {
334  STATISTICS(num_constant_expr++);
335  M->add_Instruction(foldedInst);
336  replace_by_constant(I, foldedInst, M);
337  }
338  } else if (I->get_opcode() == Instruction::PHIInstID
340  assert(I->op_size() > 0);
341  STATISTICS(num_constant_phis++);
342  CONSTInst *firstOp = I->get_operand(0)->to_Instruction()
343  ->to_CONSTInst();
344  replace_by_constant(I, firstOp, M);
345  }
346  }
347  }
348 
349  return true;
350 }
351 
352 // pass usage
357  return PU;
358 }
359 
360 // the address of this variable is used to identify the pass
362 
363 // register pass
364 static PassRegistry<ConstantPropagationPass> X("ConstantPropagationPass");
365 
366 } // end namespace compiler2
367 } // end namespace jit
368 } // end namespace cacao
369 
370 
371 /*
372  * These are local overrides for various environment variables in Emacs.
373  * Please do not remove this and leave it at the end of the file, where
374  * Emacs will automagically detect them.
375  * ---------------------------------------------------------------------
376  * Local variables:
377  * mode: c++
378  * indent-tabs-mode: t
379  * c-basic-offset: 4
380  * tab-width: 4
381  * End:
382  * vim:noexpandtab:sw=4:ts=4:
383  */
Template specialization for NEGInstID.
#define STATISTICS(x)
Wrapper for statistics only code.
Definition: statistics.hpp:975
virtual Instruction * to_Instruction()
Definition: Value.hpp:88
#define STAT_REGISTER_SUBGROUP(var, name, description, group)
Register a statistics group and add it to a group.
Definition: statistics.hpp:974
Template specialization for DIVInstID.
virtual bool run(JITData &JD)
Run the Pass.
UserListTy::const_iterator user_begin() const
Definition: Value.hpp:72
virtual CONSTInst * to_CONSTInst()
Definition: Instruction.hpp:53
WorkListTy workList
This work list is used by the algorithm to store the instructions which have to be reconsidered...
u2 op
Definition: disass.cpp:129
_Base::const_iterator const_iterator
T operator()(const T &lhs, const T &rhs) const
T operator()(const T &lhs, const T &rhs) const
T operator()(const T &lhs, const T &rhs) const
UserListTy::const_iterator user_end() const
Definition: Value.hpp:73
InstBoolMapTy inWorkList
will be used to look up whether an instruction is currently contained in the worklist to avoid insert...
InstIntMapTy constantOperands
used to track for each instruction the number of its operands which are already known to be constant ...
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
CONSTInst * foldBinaryInst(BinaryInst *inst)
CONSTInst * foldUnaryInst(UnaryInst *inst)
T operator()(const T &lhs, const T &rhs) const
void replace_value(Value *v)
Replace this Value this the new one in all users.
Definition: Value.cpp:55
T unaryOperate(Instruction::InstID ID, const T &op)
function wrapper for UnaryOperation
Template specialization for MULInstID.
Template specialization for SUBInstID.
Template specialization for ADDInstID.
Stores the interdependencies of a pass.
Definition: PassUsage.hpp:55
virtual PassUsage & get_PassUsage(PassUsage &PA) const
Set the requirements for the pass.
#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
Instruction super class.
Definition: Instruction.hpp:73
bool has_only_constant_operands(Instruction *inst)
void add_Instruction(Instruction *I)
Add instructions to a Method.
Definition: MethodC2.cpp:82
MIIterator i
T operator()(const T &lhs, const T &rhs) const
InstructionListTy::const_iterator const_iterator
Definition: MethodC2.hpp:67
const_iterator end() const
Definition: MethodC2.hpp:141
bool can_be_statically_evaluated(Instruction *inst)
CONSTInst * foldInstruction(Instruction *inst)
MIIterator e
#define LOG(STMT)
Analogous to DEBUG.
Definition: logging.hpp:91
#define I(value)
Definition: codegen.c:279
CONSTInst * castOperate(CASTInst *inst, const T &op)
UnaryOperation function object class.
#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
T binaryOperate(Instruction::InstID ID, const T &lhs, const T &rhs)
function wrapper for BinaryOperation
CONSTInst * foldCASTInst(CASTInst *inst)
static PassRegistry< BasicBlockSchedulingPass > X("BasicBlockSchedulingPass")
Nl nl
Definition: OStream.cpp:56
void replace_by_constant(Instruction *isnt, CONSTInst *c, Method *M)
void add_requires()
PassName is required.
Definition: PassUsage.hpp:78