CACAO
Matcher.cpp
Go to the documentation of this file.
1 /* src/vm/jit/compiler2/Matcher.cpp - Matcher class implementation
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 #include <string>
25 #include "toolbox/logging.hpp"
26 
27 #include "Matcher.hpp"
28 #include "Instructions.hpp"
29 
30 #define DEBUG_NAME "compiler2/Matcher"
31 
32 #define OP_LABEL(p) ((p)->get_opcode())
33 #define LEFT_CHILD(p) (getOperand(p, 0))
34 #define RIGHT_CHILD(p) (getOperand(p, 1))
35 #define STATE_LABEL(p) (state_labels[p])
36 
37 namespace cacao {
38 namespace jit {
39 namespace compiler2{
40 
41 // No Instruction class, to be used as wildcard in pattern matching
42 class NoInst : public Instruction {
43 public:
44  explicit NoInst(BeginInst* begin) : Instruction(Instruction::NoInstID, Type::VoidTypeID, begin) {}
45  virtual NoInst* to_NoInst() { return this; }
46  virtual void accept(InstructionVisitor& v, bool copyOperands) {
47  os::abort("Wildcard Instruction does not support Visitor");
48  }
49 };
50 
51 #define GENSTATIC
52 #include "Grammar.inc"
53 
54 // TODO do this somewhat less hacky
56  #include "GrammarExcludedNodes.inc"
57 };
58 const Matcher::ExcludeSetTy Matcher::excluded_nodes (tmp, tmp + sizeof(tmp)/ sizeof(tmp[0]));
59 
60 #define GENMETHODS
61 #include "Grammar.inc"
62 
63 void Matcher::run(){
64  findRoots();
65  LOG("Performing pattern matching" << nl);
66  for (DependencyMapTy::const_iterator i = roots.begin(), e = roots.end(); i != e; ++i){
67  Instruction* inst = i->first;
68  LOG("Handling root node " << inst << nl);
69  if (checkIsNodeExcluded(inst)){
70  LOG("Result: root is excluded node, must be handled manually" << nl);
71  // set dependencies usually done in label pass
72  for (Instruction::const_op_iterator it = inst->op_begin(), e = inst->op_end(); it != e; ++it){
73  Instruction* _inst = (*it)->to_Instruction();
74  if (roots.find(_inst) != roots.end()){
75  roots[inst]->insert(_inst);
76  revdeps[_inst]->insert(inst);
77  }
78  }
79  } else {
80  burm_label(inst, inst);
81  LOG("Result: " << nl);
82  dumpCover(inst, 1, 0);
83  }
84  }
85  scheduleTrees();
86 }
87 
88 // matching
90  LOG("Determining tree root nodes" << nl);
91  // Collect all instructions within basic block
93  _e = sched->inst_end(basicBlock); _i != _e; ++_i){
94  Instruction* inst = *_i;
95  // skip begin inst. as they're not part of matching
96  if (inst->to_BeginInst() ){
97  continue;
98  }
99  // skip begin/end/phi inst. as they're not part of matching
100  if (inst->to_PHIInst()){
101  phiInst.insert(inst);
102  continue;
103  }
104  inst_in_bb.insert(inst);
105  }
106 
107  for (InstSetTy::const_iterator it = inst_in_bb.begin(),
108  e = inst_in_bb.end(); it != e; ++it){
109  Instruction* inst = *it;
110 
111  // if excluded, handle manually, all ops are roots
112  if (checkIsNodeExcluded(inst)){
113  LOG("Found root: " << inst << " Reason: excluded node" << nl);
114  roots[inst] = shared_ptr<InstSetTy>(new InstSetTy());
115  revdeps[inst] = shared_ptr<InstSetTy>(new InstSetTy());
116  continue;
117  }
118 
119  // consider inst with multiple users
120  if (inst->user_size() > 1){
121  LOG("Found root: " << inst << " Reason: multiple users" << nl);
122  roots[inst] = shared_ptr<InstSetTy>(new InstSetTy());
123  revdeps[inst] = shared_ptr<InstSetTy>(new InstSetTy());
124  continue;
125  }
126 
127  // if inst has no users
128  if (inst->user_size() == 0){
129  LOG("Found root: " << inst << " Reason: no users" << nl);
130  roots[inst] = shared_ptr<InstSetTy>(new InstSetTy());
131  // not necessarily needed
132  revdeps[inst] = shared_ptr<InstSetTy>(new InstSetTy());
133  continue;
134  }
135 
136  // if users are outside of basic block
137  Instruction *user = *(inst->user_begin());
138  if (inst_in_bb.find(user) == inst_in_bb.end()){
139  LOG("Found root: " << inst << " Reason: users in another basic block" << nl);
140 
141  roots[inst] = shared_ptr<InstSetTy>(new InstSetTy());
142  // not necessarily needed
143  revdeps[inst] = shared_ptr<InstSetTy>(new InstSetTy());
144  continue;
145  }
146 
147  if (checkIsNodeExcluded(user)){
148  LOG("Found root: " << inst << " Reason: used by excluded node" << nl);
149  roots[inst] = shared_ptr<InstSetTy>(new InstSetTy());
150  revdeps[inst] = shared_ptr<InstSetTy>(new InstSetTy());
151  continue;
152  }
153  }
154  LOG("Found " << roots.size() << " roots" << nl);
155 }
156 
158  return excluded_nodes.find(inst->get_opcode()) != excluded_nodes.end();
159 }
160 
162  // always use proxy, if it already exists
163  if (instrProxies.find(op) != instrProxies.end()){
164  shared_ptr<ProxyMapByInstTy> proxyops = instrProxies[op];
165  if (proxyops->find(pos) != proxyops->end()){
166  shared_ptr<Instruction> proxy = (proxyops->find(pos)->second);
167  return &*proxy;
168  }
169  }
170 
171  bool dep = false;
172  bool no_operand = (pos >= op->op_size());
173  Instruction* operand = NULL;
174 
175  if (!no_operand){
176  // if no proxy available, get the instruction that is operand
177  operand = op->get_operand(pos)->to_Instruction();
178  // if its a dependency btw. subtrees of the BB
179  if (roots.find(operand) != roots.end())
180  dep = true;
181  }
182 
183  // if the tree requires a proxy, create and return it
184  // also track tree dependencies
185  // no_operand has to be checked first to avoid accessing null pointers
186  if (no_operand || dep ||
187  (inst_in_bb.find(operand) == inst_in_bb.end()) ||
188  (excluded_nodes.find(operand->get_opcode()) != excluded_nodes.end()) ){
189  return createProxy(op, pos, operand, dep);
190  }
191  // return actual operand
192  return operand;
193 }
194 
195 Instruction* Matcher::createProxy(Instruction* op, unsigned pos, Instruction* operand, bool dependency){
196  // create map for operator, if it does not exist
197  if (instrProxies.find(op) == instrProxies.end()){
198  instrProxies[op] = shared_ptr<ProxyMapByInstTy>(new ProxyMapByInstTy());
199  }
200  shared_ptr<ProxyMapByInstTy> proxyops = instrProxies[op];
201 
202  // create proxy
203  shared_ptr<Instruction> proxy = shared_ptr<Instruction>(new NoInst(op->get_BeginInst()));
204  (*proxyops)[pos] = proxy;
205  LOG("Creating proxy: " << op << " op " << pos << " (= " << operand << ")" << nl);
206 
207  // add dependency btw. trees
208  if (dependency){
209  Instruction* root = STATE_LABEL(op)->root;
210  roots[root]->insert(operand);
211  revdeps[operand]->insert(root);
212  LOG("Proxied operand is dependency for " << root << nl);
213  }
214  // return proxy op
215  return &*proxy;
216 }
217 
218 // debug output
219 void Matcher::dumpCover(Instruction* p, int goalnt, int indent) {
220  int eruleno = burm_rule(STATE_LABEL(p), goalnt);
221  const short *nts = burm_nts[eruleno];
222  Instruction* kids[10];
223  int i;
224 
225  std::string indentation;
226  for (i = 0; i < indent; i++)
227  indentation += " ";
228  LOG(indentation << burm_string[eruleno] << " (Rule: " << eruleno << " Root: " << p << nl);
229  burm_kids(p, eruleno, kids);
230  for (i = 0; nts[i]; i++)
231  dumpCover(kids[i], nts[i], indent + 1);
232 }
233 
235  LOG("root: " << inst << nl);
236  LOG("root deps(" << roots[inst]->size() << "):" << nl);
237  for (InstSetTy::const_iterator it = roots[inst]->begin(), e = roots[inst]->end(); it != e; ++it){
238  LOG(*it << nl);
239  }
240  LOG("revdeps(" << revdeps[inst]->size() << "):" << nl);
241  for (InstSetTy::const_iterator it = revdeps[inst]->begin(), e = revdeps[inst]->end(); it != e; ++it){
242  LOG(*it << nl);
243  }
244 }
245 
246 // scheduling and lowering
248  LOG("Scheduling:" << nl);
249  LOG("Scheduling Begin Instruction " << basicBlock << nl);
250  basicBlock->accept(*LV, true);
251 
252  LOG("Scheduling Phi Instructions:" << nl);
253  for (InstSetTy::const_iterator i = phiInst.begin(), e = phiInst.end();
254  i != e; ++i){
255  LOG((*i) << nl);
256  (*i)->accept(*LV, true);
257  }
258 
259  LOG("Dependencies btw. roots" << nl);
260  for (DependencyMapTy::const_iterator i = roots.begin(), e = roots.end(); i != e; ++i){
261  printDependencies(i->first);
262  }
263 
264  LOG("Scheduling Trees:" << nl);
265  while (roots.begin() != roots.end()){
266  LOG(roots.size() << " trees left to schedule" << nl);
267 
268  Instruction* candidate=NULL;
269  for (DependencyMapTy::const_iterator i = roots.begin(), e = roots.end(); i != e; ++i){
270  // skip if it has deps
271  if (i->second->size() > 0) continue;
272  // set candidate, if no candidate is set yet
273  if (!candidate) {
274  if (i->first->to_EndInst() && (roots.size() > 1)) continue;
275  candidate = i->first;
276  continue;
277  }
278  // set candidate, if root has more dependants
279  if (revdeps[candidate]->size() < revdeps[i->first]->size()){
280  candidate = i->first;
281  }
282  }
283 
284  LOG("Scheduling " << candidate << nl);
285  lowerTree(candidate, 1);
286 
287  // remove scheduled node from datastructures
288  for (DependencyMapTy::const_iterator i = roots.begin(), e = roots.end(); i != e; ++i){
289  i->second->erase(candidate);
290  }
291  roots.erase(candidate);
292  revdeps.erase(candidate);
293  }
294 }
295 
296 void Matcher::lowerTree(Instruction* p, int goalnt){
297  if (checkIsNodeExcluded(p)){
298  LOG("Excluded node is lowered manually" << nl);
299  p->accept(*LV, true);
300  return;
301  }
302  int eruleno = burm_rule(STATE_LABEL(p), goalnt);
303  const short *nts = burm_nts[eruleno];
304  Instruction* kids[10];
305  burm_kids(p, eruleno, kids);
306  for (int i = 0; nts[i]; i++)
307  lowerTree(kids[i], nts[i]);
308  lowerRule(p, (RuleId) eruleno);
309 }
310 
311 void Matcher::lowerRule(Instruction* inst, RuleId id){
312  if (burm_isinstruction[id]){
313  if (inst->get_opcode() == Instruction::NoInstID){
314  LOG(inst << " is wildcard, no lowering required" << nl);
315  } else {
316  LOG("Rule " << burm_templates[id] << " is basic Instruction, using LoweringVisitor" << nl);
317  inst->accept(*LV, STATE_LABEL(inst)->isLeaf);
318  }
319  } else {
320  LOG("Lowering " << inst << " with rule " << burm_templates[id] << nl);
321  LV->lowerComplex(inst, id);
322  }
323 }
324 
325 }
326 }
327 }
328 
329 /*
330  * These are local overrides for various environment variables in Emacs.
331  * Please do not remove this and leave it at the end of the file, where
332  * Emacs will automagically detect them.
333  * ---------------------------------------------------------------------
334  * Local variables:
335  * mode: c++
336  * indent-tabs-mode: t
337  * c-basic-offset: 4
338  * tab-width: 4
339  * End:
340  * vim:noexpandtab:sw=4:ts=4:
341  */
const_inst_iterator inst_end(const BeginInst *BI) const
#define STATE_LABEL(p)
Definition: Matcher.cpp:35
virtual Instruction * to_Instruction()
Definition: Value.hpp:88
virtual NoInst * to_NoInst()
Definition: Matcher.cpp:45
UserListTy::const_iterator user_begin() const
Definition: Value.hpp:72
LoweringVisitor * LV
Definition: Matcher.hpp:76
const_inst_iterator inst_begin(const BeginInst *BI) const
static const ExcludeSetTy excluded_nodes
Definition: Matcher.hpp:85
This Instruction mark the start of a basic block.
u2 op
Definition: disass.cpp:129
virtual void accept(InstructionVisitor &v, bool copyOperands)=0
Visitor.
virtual void lowerComplex(Instruction *I, int ruleId)
_Base::const_iterator const_iterator
alloc::set< Instruction * >::type InstSetTy
Definition: Matcher.hpp:62
JNIEnv jthread jobject jclass jlong size
Definition: jvmti.h:387
OperandListTy::const_iterator const_op_iterator
Definition: Instruction.hpp:80
alloc::unordered_map< int, shared_ptr< Instruction > >::type ProxyMapByInstTy
Definition: Matcher.hpp:63
InstID get_opcode() const
return the opcode of the instruction
void printDependencies(Instruction *inst)
Definition: Matcher.cpp:234
Indent indent
Definition: OStream.cpp:54
void dumpCover(Instruction *p, int goalnt, int indent)
Definition: Matcher.cpp:219
Instruction * getOperand(Instruction *op, unsigned pos)
Definition: Matcher.cpp:161
virtual void accept(InstructionVisitor &v, bool copyOperands)
Visitor.
bool checkIsNodeExcluded(Instruction *inst)
Definition: Matcher.cpp:157
Instruction * createProxy(Instruction *op, unsigned pos, Instruction *operand, bool dependency)
Definition: Matcher.cpp:195
Instruction::InstID tmp[]
Definition: Matcher.cpp:55
OptionPrefix & root()
Definition: Option.cpp:34
virtual Instruction * to_Instruction()
Instruction super class.
Definition: Instruction.hpp:73
MIIterator i
NoInst(BeginInst *begin)
Definition: Matcher.cpp:44
MIIterator pos
static void abort()
Definition: os.hpp:196
const_op_iterator op_begin() const
MIIterator e
#define LOG(STMT)
Analogous to DEBUG.
Definition: logging.hpp:91
GlobalSchedule * sched
Definition: Matcher.hpp:74
alloc::unordered_set< Instruction * >::type::const_iterator const_inst_iterator
size_t user_size() const
Get the number of (unique) users.
Definition: Value.hpp:81
virtual void accept(InstructionVisitor &v, bool copyOperands)
Visitor.
Definition: Matcher.cpp:46
virtual BeginInst * get_BeginInst() const
Get the corresponding BeginInst.
virtual BeginInst * to_BeginInst()
Definition: Instruction.hpp:89
alloc::set< Instruction::InstID >::type ExcludeSetTy
Definition: Matcher.hpp:64
void lowerRule(Instruction *inst, RuleId id)
Definition: Matcher.cpp:311
Nl nl
Definition: OStream.cpp:56
void lowerTree(Instruction *p, int goalnt)
Definition: Matcher.cpp:296
const_op_iterator op_end() const