CACAO
duplicate.cpp
Go to the documentation of this file.
1 /* src/vm/jit/loop/duplicate.cpp
2 
3  Copyright (C) 1996-2012
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 
25 #include "toolbox/logging.hpp"
26 #include "vm/jit/ir/icmd.hpp"
28 
29 #include "duplicate.hpp"
30 #include "Value.hpp"
31 #include "ValueMap.hpp"
32 #include "DynamicVector.hpp"
33 
34 #include <cstring>
35 
36 namespace
37 {
38  basicblock* duplicateBasicblock(const basicblock* block);
39  basicblock* createBasicblock(jitdata* jd, s4 numInstructions);
40  bool checkLoop(jitdata* jd, LoopContainer* loop);
41  void duplicateLoop(jitdata* jd, LoopContainer* loop);
42  void buildBasicblockList(jitdata* jd, LoopContainer* loop, basicblock* beforeLoop, basicblock* lastBlockInLoop, basicblock* loopSwitch, basicblock* loopTrampoline);
43  void buildBasicblockList(jitdata* jd, LoopContainer* loop, basicblock* beforeLoop, basicblock* lastBlockInLoop, basicblock* loopSwitch1, basicblock* loopSwitch2, basicblock* loopTrampoline);
44  void buildBasicblockList(jitdata* jd, LoopContainer* loop, basicblock* beforeLoop, basicblock* lastBlockInLoop, basicblock* loopSwitch1, basicblock* loopSwitch2, basicblock* loopSwitch3, basicblock* loopTrampoline);
45  void removeChecks(LoopContainer* loop, s4 array, s4 index);
46  basicblock* createTrampoline(basicblock* target);
47  void redirectJumps(jitdata* jd, basicblock* loopSwitch);
48  void optimizeLoop(jitdata* jd, LoopContainer* loop);
49  bool isLocalIntVar(jitdata* jd, s4 varIndex);
50 
51 
52  // //
53  // Functions that generate intermediate instructions. //
54  // //
55 
56  inline void opcode_ALOAD(instruction* instr, s4 src, s4 dst)
57  {
58  instr->opc = ICMD_ALOAD;
59  instr->s1.varindex = src;
60  instr->dst.varindex = dst;
61  }
62 
63  inline void opcode_ILOAD(instruction* instr, s4 src, s4 dst)
64  {
65  instr->opc = ICMD_ILOAD;
66  instr->s1.varindex = src;
67  instr->dst.varindex = dst;
68  }
69 
70  inline void opcode_ARRAYLENGTH(instruction* instr, s4 src, s4 dst)
71  {
72  instr->opc = ICMD_ARRAYLENGTH;
73  instr->s1.varindex = src;
74  instr->dst.varindex = dst;
75  }
76 
77  inline void opcode_IADDCONST(instruction* instr, s4 src, s4 constant, s4 dst)
78  {
79  instr->opc = ICMD_IADDCONST;
80  instr->s1.varindex = src;
81  instr->sx.val.i = constant;
82  instr->dst.varindex = dst;
83  }
84 
85  inline void opcode_ISUBCONST(instruction* instr, s4 src, s4 constant, s4 dst)
86  {
87  instr->opc = ICMD_ISUBCONST;
88  instr->s1.varindex = src;
89  instr->sx.val.i = constant;
90  instr->dst.varindex = dst;
91  }
92 
93  inline void opcode_GOTO(instruction* instr, basicblock* dst)
94  {
95  instr->opc = ICMD_GOTO;
96  instr->dst.block = dst;
97  }
98 
99  inline void opcode_IFGT(instruction* instr, s4 src, s4 constant, basicblock* dst)
100  {
101  instr->opc = ICMD_IFGT;
102  instr->s1.varindex = src;
103  instr->sx.val.i = constant;
104  instr->dst.block = dst;
105  }
106 
107  inline void opcode_IFLT(instruction* instr, s4 src, s4 constant, basicblock* dst)
108  {
109  instr->opc = ICMD_IFLT;
110  instr->s1.varindex = src;
111  instr->sx.val.i = constant;
112  instr->dst.block = dst;
113  }
114 
115  inline void opcode_IFLE(instruction* instr, s4 src, s4 constant, basicblock* dst)
116  {
117  instr->opc = ICMD_IFLE;
118  instr->s1.varindex = src;
119  instr->sx.val.i = constant;
120  instr->dst.block = dst;
121  }
122 
123  inline void opcode_IFNULL(instruction* instr, s4 src, basicblock* dst)
124  {
125  instr->opc = ICMD_IFNULL;
126  instr->s1.varindex = src;
127  instr->dst.block = dst;
128  }
129 
130  inline void opcode_IF_ICMPGE(instruction* instr, s4 src1, s4 src2, basicblock* dst)
131  {
132  instr->opc = ICMD_IF_ICMPGE;
133  instr->s1.varindex = src1;
134  instr->sx.s23.s2.varindex = src2;
135  instr->dst.block = dst;
136  }
137 
138  ////////////////////////////////////////////////////////
139 
140 
141  basicblock* duplicateBasicblock(const basicblock* block)
142  {
143  // flat clone
144  basicblock* clone = new basicblock(*block);
145  clone->ld = new BasicblockLoopData;
146 
147  // clone instructions
148  clone->iinstr = new instruction[block->icount];
149  memcpy(clone->iinstr, block->iinstr, sizeof(instruction) * block->icount);
150 
151  // clone table- and lookup-switches
152  for (s4 i = 0; i < block->icount; i++)
153  {
154  instruction* instr = &block->iinstr[i];
155  switch (instr->opc)
156  {
157  case ICMD_TABLESWITCH:
158  {
159  // count = (tablehigh - tablelow + 1) + 1 [default branch]
160  s4 count = instr->sx.s23.s3.tablehigh - instr->sx.s23.s2.tablelow + 2;
161 
162  // clone switch table
163  clone->iinstr[i].dst.table = new branch_target_t[count];
164  memcpy(clone->iinstr[i].dst.table, instr->dst.table, sizeof(branch_target_t) * count);
165  break;
166  }
167  case ICMD_LOOKUPSWITCH:
168  {
169  s4 count = instr->sx.s23.s2.lookupcount;
170 
171  // clone lookup table
172  clone->iinstr[i].dst.lookup = new lookup_target_t[count];
173  memcpy(clone->iinstr[i].dst.lookup, instr->dst.lookup, sizeof(lookup_target_t) * count);
174  break;
175  }
176  }
177  }
178 
179  return clone;
180  }
181 
182  basicblock* createBasicblock(jitdata* jd, s4 numInstructions)
183  {
184  basicblock* block = new basicblock;
185  memset(block, 0, sizeof(basicblock));
186  block->ld = new BasicblockLoopData;
187  block->method = jd->m;
188  block->state = basicblock::FINISHED;
189  block->mpc = -1;
190  block->icount = numInstructions;
191  block->iinstr = new instruction[numInstructions];
192  memset(block->iinstr, 0, sizeof(instruction) * numInstructions);
193  return block;
194  }
195 
196  /**
197  * Creates a basicblock with a single GOTO instruction.
198  */
199  basicblock* createTrampoline(jitdata* jd, basicblock* target)
200  {
201  basicblock* trampoline = createBasicblock(jd, 1);
202  opcode_GOTO(trampoline->iinstr, target);
203  return trampoline;
204  }
205 
206  void duplicateLoop(LoopContainer* loop)
207  {
208  // copy header
209  loop->header->ld->copiedTo = duplicateBasicblock(loop->header);
210 
211  // copy other basicblocks
212  for (std::vector<basicblock*>::iterator it = loop->nodes.begin(); it != loop->nodes.end(); ++it)
213  {
214  (*it)->ld->copiedTo = duplicateBasicblock(*it);
215  }
216  }
217 
218  /**
219  * Returns true (otherwise false) if the following points hold for the specified loop:
220  *
221  * -) The loop does not contain a hole.
222  * -) The first block is the header.
223  * -) The stack depth before and after the loop is 0.
224  *
225  * The above points simplify the code generation.
226  *
227  * The arguments beforeLoopPtr and lastBlockInLoopPtr will be set
228  * to the basicblock before the loop and to the last basicblock in the loop respectively.
229  */
230  bool checkLoop(jitdata* jd, LoopContainer* loop, basicblock** beforeLoopPtr, basicblock** lastBlockInLoopPtr)
231  {
232  *beforeLoopPtr = 0;
233  *lastBlockInLoopPtr = 0;
234 
235  // Mark every basicblock which is part of the loop
236  loop->header->ld->belongingTo = loop;
237  for (std::vector<basicblock*>::iterator it = loop->nodes.begin(); it != loop->nodes.end(); ++it)
238  {
239  (*it)->ld->belongingTo = loop;
240  }
241 
242 
243  basicblock* lastBlock = 0;
244  bool loopFound = false;
245 
246  // Analyze marked basicblocks.
247  for (basicblock* block = jd->basicblocks; block; block = block->next)
248  {
249  if (block->ld->belongingTo == loop)
250  {
251  // Are we entering the loop?
252  if (lastBlock == 0 || lastBlock->ld->belongingTo != loop) // lastBlock is not part of the loop
253  {
254  // The loop contains a hole.
255  if (loopFound)
256  {
257  //log_text("checkLoop: hole");
258  return false;
259  }
260 
261  // The first block is not the header.
262  if (block->ld->loop == 0)
263  {
264  //log_text("checkLoop: header");
265  return false;
266  }
267 
268  loopFound = true;
269  *beforeLoopPtr = lastBlock;
270  }
271 
272  *lastBlockInLoopPtr = block;
273  }
274 
275  lastBlock = block;
276  }
277 
278  // Check stack depth.
279  if (loop->header->indepth != 0 || (*lastBlockInLoopPtr)->outdepth != 0)
280  {
281  //log_text("checkLoop: stack depth");
282  return false;
283  }
284 
285  return true;
286  }
287 
288  inline void buildBasicblockList(jitdata* jd, LoopContainer* loop, basicblock* beforeLoop, basicblock* lastBlockInLoop, basicblock* loopSwitch, basicblock* loopTrampoline)
289  {
290  buildBasicblockList(jd, loop, beforeLoop, lastBlockInLoop, loopSwitch, 0, 0, loopTrampoline);
291  }
292 
293  inline void buildBasicblockList(jitdata* jd, LoopContainer* loop, basicblock* beforeLoop, basicblock* lastBlockInLoop, basicblock* loopSwitch1, basicblock* loopSwitch2, basicblock* loopTrampoline)
294  {
295  buildBasicblockList(jd, loop, beforeLoop, lastBlockInLoop, loopSwitch1, loopSwitch2, 0, loopTrampoline);
296  }
297 
298  /**
299  * Inserts the copied loop, the loop switches and the trampoline into the global basicblock list.
300  * It also inserts these nodes into the predecessor loops.
301  *
302  * loop: The original loop that has been duplicated.
303  * loopSwitch2: Will be inserted after the first loop switch if it is != 0.
304  * loopSwitch3: Will be inserted after the first loop switch if it is != 0.
305  */
306  void buildBasicblockList(jitdata* jd, LoopContainer* loop, basicblock* beforeLoop, basicblock* lastBlockInLoop, basicblock* loopSwitch1, basicblock* loopSwitch2, basicblock* loopSwitch3, basicblock* loopTrampoline)
307  {
308  assert(loopSwitch1);
309 
310  // insert first loop switch
311  if (beforeLoop)
312  {
313  loopSwitch1->next = beforeLoop->next;
314  beforeLoop->next = loopSwitch1;
315  }
316  else
317  {
318  loopSwitch1->next = jd->basicblocks;
319  jd->basicblocks = loopSwitch1;
320  }
321 
322  basicblock* lastLoopSwitch = loopSwitch1;
323 
324  // insert second loop switch
325  if (loopSwitch2)
326  {
327  loopSwitch2->next = lastLoopSwitch->next;
328  lastLoopSwitch->next = loopSwitch2;
329 
330  lastLoopSwitch = loopSwitch2;
331  }
332 
333  // insert third loop switch
334  if (loopSwitch3)
335  {
336  loopSwitch3->next = lastLoopSwitch->next;
337  lastLoopSwitch->next = loopSwitch3;
338 
339  lastLoopSwitch = loopSwitch3;
340  }
341 
342  // insert trampoline after loop
343  lastBlockInLoop->next = loopTrampoline;
344 
345  // The basicblocks contained in the following container will be inserted into the predecessor loops.
346  std::vector<basicblock*> duplicates;
347  duplicates.reserve(loop->nodes.size() + 1);
348 
349  // insert copied loop after trampoline
350  basicblock* end = loopTrampoline;
351  for (basicblock* block = lastLoopSwitch->next; block != loopTrampoline; block = block->next)
352  {
353  end->next = block->ld->copiedTo;
354  end = block->ld->copiedTo;
355 
356  // The copied basicblock must be inserted into the predecessor loops.
357  duplicates.push_back(block->ld->copiedTo);
358 
359  // prepare for next loop duplication
360  block->ld->copiedTo = 0;
361  }
362 
363  // end->next already points to the basicblock after the second loop.
364 
365  // Insert nodes into predecessor loops except the root loop.
366  for (LoopContainer* pred = loop->parent; pred->parent; pred = pred->parent)
367  {
368  for (std::vector<basicblock*>::iterator it = duplicates.begin(); it != duplicates.end(); ++it)
369  {
370  pred->nodes.push_back(*it);
371  }
372  pred->nodes.push_back(loopTrampoline);
373  pred->nodes.push_back(loopSwitch1);
374  if (loopSwitch2)
375  pred->nodes.push_back(loopSwitch2);
376  if (loopSwitch3)
377  pred->nodes.push_back(loopSwitch3);
378  }
379  }
380 
381  void removeChecks(LoopContainer* loop, s4 array, s4 index)
382  {
383  for (std::vector<basicblock*>::iterator it = loop->nodes.begin(); it != loop->nodes.end(); ++it)
384  {
385  for (instruction* instr = (*it)->iinstr; instr != (*it)->iinstr + (*it)->icount; instr++)
386  {
387  switch (instr->opc)
388  {
389  case ICMD_IALOAD:
390  case ICMD_LALOAD:
391  case ICMD_FALOAD:
392  case ICMD_DALOAD:
393  case ICMD_AALOAD:
394  case ICMD_BALOAD:
395  case ICMD_CALOAD:
396  case ICMD_SALOAD:
397 
398  case ICMD_IASTORE:
399  case ICMD_LASTORE:
400  case ICMD_FASTORE:
401  case ICMD_DASTORE:
402  case ICMD_AASTORE:
403  case ICMD_BASTORE:
404  case ICMD_CASTORE:
405  case ICMD_SASTORE:
406 
407  case ICMD_IASTORECONST:
408  case ICMD_LASTORECONST:
409  case ICMD_FASTORECONST:
410  case ICMD_DASTORECONST:
411  case ICMD_AASTORECONST:
412  case ICMD_BASTORECONST:
413  case ICMD_CASTORECONST:
414  case ICMD_SASTORECONST:
415 
416  if (array == instr->s1.varindex && index == instr->sx.s23.s2.varindex)
417  instr->flags.bits &= ~INS_FLAG_CHECK;
418  break;
419  }
420  }
421  }
422  }
423 
424  /**
425  * Redirects all jumps that go to the old loop:
426  * -) A jump from outside of the loop will be redirected to the loop switch.
427  * -) A jump from the duplicate will be redirected to the duplicate.
428  *
429  * This function must be called before the duplicate is inserted into the linked list.
430  */
431  void redirectJumps(jitdata* jd, basicblock* loopSwitch)
432  {
433  // All jumps that go from the outside of the loop to the loop header must be redirected to the loop switch.
434  for (basicblock* block = jd->basicblocks; block; block = block->next)
435  {
436  // Check if this block is not part of the original loop.
437  if (!block->ld->copiedTo)
438  {
439  for (instruction* instr = block->iinstr; instr != block->iinstr + block->icount; instr++)
440  {
441  // If instr is a jump into the original loop, redirect it to the loop switch.
442  switch (icmd_table[instr->opc].controlflow)
443  {
444  case CF_IF:
445  case CF_GOTO:
446  case CF_RET:
447  if (instr->dst.block->ld->copiedTo)
448  instr->dst.block = loopSwitch;
449  break;
450  case CF_JSR:
451  if (instr->sx.s23.s3.jsrtarget.block->ld->copiedTo)
452  instr->sx.s23.s3.jsrtarget.block = loopSwitch;
453  break;
454  case CF_TABLE:
455  {
456  // count = (tablehigh - tablelow + 1) + 1 [default branch]
457  s4 count = instr->sx.s23.s3.tablehigh - instr->sx.s23.s2.tablelow + 2;
458 
459  branch_target_t* target = instr->dst.table;
460  while (--count >= 0)
461  {
462  if (target->block->ld->copiedTo)
463  target->block = loopSwitch;
464  target++;
465  }
466  break;
467  }
468  case CF_LOOKUP:
469  {
470  // default target
471  if (instr->sx.s23.s3.lookupdefault.block->ld->copiedTo)
472  instr->sx.s23.s3.lookupdefault.block = loopSwitch;
473 
474  // other targets
475  lookup_target_t* entry = instr->dst.lookup;
476  s4 count = instr->sx.s23.s2.lookupcount;
477  while (--count >= 0)
478  {
479  if (entry->target.block->ld->copiedTo)
480  entry->target.block = loopSwitch;
481  entry++;
482  }
483  break;
484  }
485  case CF_END:
486  case CF_NORMAL:
487  // nothing
488  break;
489  }
490  }
491  }
492  else // This block is part of the original loop.
493  {
494  // Redirect jumps that go from the duplicate to the original loop.
495  basicblock* dupBlock = block->ld->copiedTo;
496  for (instruction* instr = dupBlock->iinstr; instr != dupBlock->iinstr + dupBlock->icount; instr++)
497  {
498  // If instr is a jump into the original loop, redirect it to the duplicated block.
499  switch (icmd_table[instr->opc].controlflow)
500  {
501  case CF_IF:
502  case CF_GOTO:
503  case CF_RET:
504  if (instr->dst.block->ld->copiedTo)
505  instr->dst.block = instr->dst.block->ld->copiedTo;
506  break;
507  case CF_JSR:
508  if (instr->sx.s23.s3.jsrtarget.block->ld->copiedTo)
509  instr->sx.s23.s3.jsrtarget.block = instr->sx.s23.s3.jsrtarget.block->ld->copiedTo;
510  break;
511  case CF_TABLE:
512  {
513  // count = (tablehigh - tablelow + 1) + 1 [default branch]
514  s4 count = instr->sx.s23.s3.tablehigh - instr->sx.s23.s2.tablelow + 2;
515 
516  branch_target_t* target = instr->dst.table;
517  while (--count >= 0)
518  {
519  if (target->block->ld->copiedTo)
520  target->block = target->block->ld->copiedTo;
521  target++;
522  }
523  break;
524  }
525  case CF_LOOKUP:
526  {
527  // default target
528  if (instr->sx.s23.s3.lookupdefault.block->ld->copiedTo)
529  instr->sx.s23.s3.lookupdefault.block = instr->sx.s23.s3.lookupdefault.block->ld->copiedTo;
530 
531  // other targets
532  lookup_target_t* entry = instr->dst.lookup;
533  s4 count = instr->sx.s23.s2.lookupcount;
534  while (--count >= 0)
535  {
536  if (entry->target.block->ld->copiedTo)
537  entry->target.block = entry->target.block->ld->copiedTo;
538  entry++;
539  }
540  break;
541  }
542  case CF_END:
543  case CF_NORMAL:
544  // nothing
545  break;
546  }
547  }
548  }
549  }
550  }
551 
552  void optimizeLoop(jitdata* jd, LoopContainer* loop)
553  {
554  // Optimize inner loops.
555  for (std::vector<LoopContainer*>::iterator it = loop->children.begin(); it != loop->children.end(); ++it)
556  {
557  optimizeLoop(jd, *it);
558  }
559 
560  // Currently only loops with one footer are optimized.
561  if (loop->footers.size() == 1 && loop->hasCounterVariable)
562  {
563  if (loop->counterIncrement >= 0 && loop->counterInterval.lower().lower() >= 0)
564  {
565  // counterInterval: [L, ?], L >= 0
566 
568  loop->counterInterval.upper().constant() < 0)
569  {
570  // counterInterval: [L, array.length - c], L >= 0, c > 0
571 
572  //log_text("optimizeLoop: [non-negative, arraylength], inc");
573 
574  s4 array = loop->counterInterval.upper().instruction().variable();
575 
576  // The array variable must be invariant.
577  if (!loop->invariantArrays.contains(array))
578  {
579  //log_println("optimizeLoop: %d not invariant", array);
580  return;
581  }
582 
583  basicblock *beforeLoop, *lastBlockInLoop;
584  if (!checkLoop(jd, loop, &beforeLoop, &lastBlockInLoop))
585  return;
586 
587  duplicateLoop(loop);
588 
589  // remove checks in original loop
590  removeChecks(loop, array, loop->counterVariable);
591 
592  // create basicblocks that jump to the right loop
593  basicblock* loopSwitch1 = createBasicblock(jd, 2);
594  basicblock* loopSwitch2 = createBasicblock(jd, 4);
595  instruction* instr;
596 
597  // Fill instruction array of first loop switch with:
598  // if (array == null) goto unoptimized_loop
599 
600  instr = loopSwitch1->iinstr;
601 
602  opcode_ALOAD(instr++, array, array);
603  opcode_IFNULL(instr++, array, loop->header->ld->copiedTo);
604 
605  assert(instr - loopSwitch1->iinstr == loopSwitch1->icount);
606 
607  // Fill instruction array of second loop switch with:
608  // if (array.length + upper_constant > MAX - increment) goto unoptimized_loop
609 
610  instr = loopSwitch2->iinstr;
611 
612  opcode_ALOAD(instr++, array, array);
613  opcode_ARRAYLENGTH(instr++, array, jd->ld->freeVariable);
614  opcode_IADDCONST(instr++, jd->ld->freeVariable, loop->counterInterval.upper().constant(), jd->ld->freeVariable);
615  opcode_IFGT(instr++, jd->ld->freeVariable, Scalar::max() - loop->counterIncrement, loop->header->ld->copiedTo);
616 
617  assert(instr - loopSwitch2->iinstr == loopSwitch2->icount);
618 
619  // create basicblock that jumps over the second loop
620  basicblock* loopTrampoline = createTrampoline(jd, lastBlockInLoop->next);
621 
622  // Insert loop into basicblock list.
623  redirectJumps(jd, loopSwitch1);
624  buildBasicblockList(jd, loop, beforeLoop, lastBlockInLoop, loopSwitch1, loopSwitch2, loopTrampoline);
625 
626  // Adjust statistical data.
627  jd->basicblockcount += loop->nodes.size() + 4;
628  }
630  loop->counterInterval.upper().constant() == 0)
631  {
632  // counterInterval: [L, x], L >= 0
633 
634  //log_text("optimizeLoop: [non-negative, invariant], inc");
635 
636  if (loop->invariantArrays.begin() == loop->invariantArrays.end())
637  {
638  //log_text("optimizeLoop: no invariant array");
639  return;
640  }
641 
642  // possible optimization: why take an arbitrary array variable?
643  s4 array = *loop->invariantArrays.begin();
644 
645  basicblock *beforeLoop, *lastBlockInLoop;
646  if (!checkLoop(jd, loop, &beforeLoop, &lastBlockInLoop))
647  return;
648 
649  duplicateLoop(loop);
650 
651  // remove checks in original loop
652  removeChecks(loop, array, loop->counterVariable);
653 
654  s4 invariantVariable = loop->counterInterval.upper().instruction().variable();
655 
656  // create loop switches that jump to the right loop
657  basicblock* loopSwitch1 = createBasicblock(jd, 2);
658  basicblock* loopSwitch2 = createBasicblock(jd, 2);
659  basicblock* loopSwitch3 = createBasicblock(jd, 4);
660  instruction* instr;
661 
662  // Fill instruction array of first loop switch with:
663  // if (invariant > MAX - increment) goto unoptimized_loop
664 
665  instr = loopSwitch1->iinstr;
666 
667  opcode_ILOAD(instr++, invariantVariable, invariantVariable);
668  opcode_IFGT(instr++, invariantVariable, Scalar::max() - loop->counterIncrement, loop->header->ld->copiedTo);
669 
670  assert(instr - loopSwitch1->iinstr == loopSwitch1->icount);
671 
672  // Fill instruction array of second loop switch with:
673  // if (array == null) goto unoptimized_loop
674 
675  instr = loopSwitch2->iinstr;
676 
677  opcode_ALOAD(instr++, array, array);
678  opcode_IFNULL(instr++, array, loop->header->ld->copiedTo);
679 
680  assert(instr - loopSwitch2->iinstr == loopSwitch2->icount);
681 
682  // Fill instruction array of third loop switch with:
683  // if (invariant >= array.length) goto unoptimized_loop
684 
685  instr = loopSwitch3->iinstr;
686 
687  opcode_ILOAD(instr++, invariantVariable, invariantVariable);
688  opcode_ALOAD(instr++, array, array);
689  opcode_ARRAYLENGTH(instr++, array, jd->ld->freeVariable);
690  opcode_IF_ICMPGE(instr++, invariantVariable, jd->ld->freeVariable, loop->header->ld->copiedTo);
691 
692  assert(instr - loopSwitch3->iinstr == loopSwitch3->icount);
693 
694  // create basicblock that jumps over the second loop
695  basicblock* loopTrampoline = createTrampoline(jd, lastBlockInLoop->next);
696 
697  // Insert loop into basicblock list.
698  redirectJumps(jd, loopSwitch1);
699  buildBasicblockList(jd, loop, beforeLoop, lastBlockInLoop, loopSwitch1, loopSwitch2, loopSwitch3, loopTrampoline);
700 
701  // Adjust statistical data.
702  jd->basicblockcount += loop->nodes.size() + 5;
703  }
706  {
707  // counterInterval: [L, c], L >= 0, c <= MAX - increment
708 
709  //log_text("optimizeLoop: [non-negative, constant], inc");
710 
711  if (loop->invariantArrays.begin() == loop->invariantArrays.end())
712  {
713  //log_text("optimizeLoop: no invariant array");
714  return;
715  }
716 
717  // possible optimization: why take an arbitrary array variable?
718  s4 array = *loop->invariantArrays.begin();
719 
720  basicblock *beforeLoop, *lastBlockInLoop;
721  if (!checkLoop(jd, loop, &beforeLoop, &lastBlockInLoop))
722  return;
723 
724  duplicateLoop(loop);
725 
726  // remove checks in original loop
727  removeChecks(loop, array, loop->counterVariable);
728 
729  // create basicblock that jumps to the right loop
730  basicblock* loopSwitch1 = createBasicblock(jd, 2);
731  basicblock* loopSwitch2 = createBasicblock(jd, 3);
732  instruction* instr;
733 
734  // Fill instruction array of first loop switch with:
735  // if (array == null) goto unoptimized_loop
736 
737  instr = loopSwitch1->iinstr;
738 
739  opcode_ALOAD(instr++, array, array);
740  opcode_IFNULL(instr++, array, loop->header->ld->copiedTo);
741 
742  assert(instr - loopSwitch1->iinstr == loopSwitch1->icount);
743 
744  // Fill instruction array of second loop switch with:
745  // if (array.length <= upper_constant) goto unoptimized_loop
746 
747  instr = loopSwitch2->iinstr;
748 
749  opcode_ALOAD(instr++, array, array);
750  opcode_ARRAYLENGTH(instr++, array, jd->ld->freeVariable);
751  opcode_IFLE(instr++, jd->ld->freeVariable, loop->counterInterval.upper().constant(), loop->header->ld->copiedTo);
752 
753  assert(instr - loopSwitch2->iinstr == loopSwitch2->icount);
754 
755  // create basicblock that jumps over the second loop
756  basicblock* loopTrampoline = createTrampoline(jd, lastBlockInLoop->next);
757 
758  // Insert loop into basicblock list.
759  redirectJumps(jd, loopSwitch1);
760  buildBasicblockList(jd, loop, beforeLoop, lastBlockInLoop, loopSwitch1, loopSwitch2, loopTrampoline);
761 
762  // Adjust statistical data.
763  jd->basicblockcount += loop->nodes.size() + 4;
764  }
765  }
766  else if (loop->counterIncrement < 0 &&
768  loop->counterInterval.upper().constant() < 0)
769  {
770  // counterInterval: [?, U], U < array.length
771 
773  loop->counterInterval.lower().constant() >= 0)
774  {
775  // counterInterval: [c, U], c >= 0, U < array.length
776 
777  //log_text("optimizeLoop: [non-negative, arraylength], dec");
778 
779  s4 array = loop->counterInterval.upper().instruction().variable();
780 
781  // The array variable must be invariant.
782  if (!loop->invariantArrays.contains(array))
783  {
784  //log_println("optimizeLoop: %d not invariant", array);
785  return;
786  }
787 
788  // No runtime check and so no loop duplication is necessary.
789 
790  // remove checks in loop
791  removeChecks(loop, array, loop->counterVariable);
792  }
794  loop->counterInterval.lower().constant() == 0)
795  {
796  // counterInterval: [x, U], U < array.length
797 
798  //log_text("optimizeLoop: [invariant, arraylength], dec");
799 
800  s4 array = loop->counterInterval.upper().instruction().variable();
801 
802  // The array variable must be invariant.
803  if (!loop->invariantArrays.contains(array))
804  {
805  //log_println("optimizeLoop: %d not invariant", array);
806  return;
807  }
808 
809  basicblock *beforeLoop, *lastBlockInLoop;
810  if (!checkLoop(jd, loop, &beforeLoop, &lastBlockInLoop))
811  return;
812 
813  duplicateLoop(loop);
814 
815  // remove checks in original loop
816  removeChecks(loop, array, loop->counterVariable);
817 
818  s4 invariantVariable = loop->counterInterval.lower().instruction().variable();
819 
820  // create basicblock that jumps to the right loop
821  basicblock* loopSwitch = createBasicblock(jd, 2);
822 
823  // Fill instruction array of loop switch with:
824  // if (invariant < 0) goto unoptimized_loop
825 
826  instruction* instr = loopSwitch->iinstr;
827 
828  opcode_ILOAD(instr++, invariantVariable, invariantVariable);
829  opcode_IFLT(instr++, invariantVariable, 0, loop->header->ld->copiedTo);
830 
831  assert(instr - loopSwitch->iinstr == loopSwitch->icount);
832 
833  // create basicblock that jumps over the second loop
834  basicblock* loopTrampoline = createTrampoline(jd, lastBlockInLoop->next);
835 
836  // Insert loop into basicblock list.
837  redirectJumps(jd, loopSwitch);
838  buildBasicblockList(jd, loop, beforeLoop, lastBlockInLoop, loopSwitch, loopTrampoline);
839 
840  // Adjust statistical data.
841  jd->basicblockcount += loop->nodes.size() + 3;
842  }
844  loop->counterInterval.lower().constant() < 0 &&
845  loop->counterInterval.lower().constant() > Scalar::min()) // prevent overflow during negation
846  {
847  // counterInterval: [array.length + c, U], MIN < c < 0, U < array.length
848 
849  //log_text("optimizeLoop: [arraylength, arraylength], dec");
850 
851  s4 array = loop->counterInterval.upper().instruction().variable();
852 
853  // Both array variables must be the same.
854  if (array != loop->counterInterval.lower().instruction().variable())
855  {
856  //log_text("optimizeLoop: arrays are different");
857  return;
858  }
859 
860  // The array variable must be invariant.
861  if (!loop->invariantArrays.contains(array))
862  {
863  //log_println("optimizeLoop: %d not invariant", array);
864  return;
865  }
866 
867  basicblock *beforeLoop, *lastBlockInLoop;
868  if (!checkLoop(jd, loop, &beforeLoop, &lastBlockInLoop))
869  return;
870 
871  duplicateLoop(loop);
872 
873  // remove checks in original loop
874  removeChecks(loop, array, loop->counterVariable);
875 
876  // create basicblock that jumps to the right loop
877  basicblock* loopSwitch = createBasicblock(jd, 3);
878 
879  // Fill instruction array of loop switch with:
880  // if (array.length < -1 * lower_constant) goto unoptimized_loop
881 
882  instruction* instr = loopSwitch->iinstr;
883 
884  opcode_ALOAD(instr++, array, array);
885  opcode_ARRAYLENGTH(instr++, array, jd->ld->freeVariable);
886  opcode_IFLT(instr++, jd->ld->freeVariable, -loop->counterInterval.lower().constant(), loop->header->ld->copiedTo);
887 
888  assert(instr - loopSwitch->iinstr == loopSwitch->icount);
889 
890  // create basicblock that jumps over the second loop
891  basicblock* loopTrampoline = createTrampoline(jd, lastBlockInLoop->next);
892 
893  // Insert loop into basicblock list.
894  redirectJumps(jd, loopSwitch);
895  buildBasicblockList(jd, loop, beforeLoop, lastBlockInLoop, loopSwitch, loopTrampoline);
896 
897  // Adjust statistical data.
898  jd->basicblockcount += loop->nodes.size() + 3;
899  }
900  }
901  }
902  }
903 
904  /**
905  * Checks whether the specified variable is local and of type integer.
906  */
907  bool isLocalIntVar(jitdata* jd, s4 varIndex)
908  {
909  varinfo* info = VAR(varIndex);
910  return IS_INT_TYPE(info->type) && (var_is_local(jd, varIndex) || var_is_temp(jd, varIndex));
911  }
912 }
913 
915 {
916  // Reserve temporary variable.
917  if (jd->vartop < jd->varcount)
918  {
919  jd->ld->freeVariable = jd->vartop++;
920 
921  varinfo* v = VAR(jd->ld->freeVariable);
922  v->type = TYPE_INT;
923 
924  return true;
925  }
926 
927  return false;
928 }
929 
931 {
932  for (std::vector<LoopContainer*>::iterator it = jd->ld->rootLoop->children.begin(); it != jd->ld->rootLoop->children.end(); ++it)
933  {
934  optimizeLoop(jd, *it);
935  }
936 }
937 
939 {
940  bool optimizationDone = false;
941  basicblock* lastBlock = 0;
942 
943  // Optimize every basicblock separately.
944  for (basicblock* block = jd->basicblocks; block; lastBlock = block, block = block->next)
945  {
946  // makes block duplication simpler
947  if (block->indepth != 0 || block->outdepth != 0)
948  continue;
949 
950  // A variable v is mapped to the value w+c, where w represents the value the variable w has at the beginning of the block.
951  // At the beginning of a basicblock every variable v has the value v+0.
952  ValueMap values;
953 
954  // first index: array variable
955  // second index: index variable
956  DynamicVector<DynamicVector<s4> > smallestConstants;
957  DynamicVector<DynamicVector<s4> > biggestConstants;
958  DynamicVector<DynamicVector<s4> > accessCounts;
959 
960  std::vector<s4> instructionArrayMap; // Maps each instruction index to the used array variable.
961  std::vector<s4> instructionIndexMap; // Maps each instruction index to the used index variable.
962 
963  instructionArrayMap.resize(block->icount);
964  instructionIndexMap.resize(block->icount);
965 
966  for (s4 i = 0; i < block->icount; i++)
967  {
968  instruction* instr = &block->iinstr[i];
969 
970  switch (instr->opc)
971  {
972  case ICMD_COPY:
973  case ICMD_MOVE:
974  case ICMD_ILOAD:
975  case ICMD_ISTORE:
976  if (isLocalIntVar(jd, instr->dst.varindex))
977  values[instr->dst.varindex] = values[instr->s1.varindex];
978  else
979  values[instr->dst.varindex] = Value::newUnknown(); // dst can be an array
980  break;
981 
982  case ICMD_IINC:
983  case ICMD_IADDCONST:
984  if (isLocalIntVar(jd, instr->dst.varindex))
985  {
986  values[instr->dst.varindex] = values[instr->s1.varindex];
987  values[instr->dst.varindex].addConstant(instr->sx.val.i);
988  }
989  break;
990 
991  case ICMD_ISUBCONST:
992  if (isLocalIntVar(jd, instr->dst.varindex))
993  {
994  values[instr->dst.varindex] = values[instr->s1.varindex];
995  values[instr->dst.varindex].subtractConstant(instr->sx.val.i);
996  }
997  break;
998 
999  case ICMD_IALOAD:
1000  case ICMD_LALOAD:
1001  case ICMD_FALOAD:
1002  case ICMD_DALOAD:
1003  case ICMD_AALOAD:
1004  case ICMD_BALOAD:
1005  case ICMD_CALOAD:
1006  case ICMD_SALOAD:
1007 
1008  case ICMD_IASTORE:
1009  case ICMD_LASTORE:
1010  case ICMD_FASTORE:
1011  case ICMD_DASTORE:
1012  case ICMD_AASTORE:
1013  case ICMD_BASTORE:
1014  case ICMD_CASTORE:
1015  case ICMD_SASTORE:
1016 
1017  case ICMD_IASTORECONST:
1018  case ICMD_LASTORECONST:
1019  case ICMD_FASTORECONST:
1020  case ICMD_DASTORECONST:
1021  case ICMD_AASTORECONST:
1022  case ICMD_BASTORECONST:
1023  case ICMD_CASTORECONST:
1024  case ICMD_SASTORECONST:
1025  {
1026  // the value of the index variable
1027  const Value& value = values[instr->sx.s23.s2.varindex];
1028  s4 array = instr->s1.varindex;
1029 
1030  if (!value.isUnknown() &&
1031  (instr->flags.bits & INS_FLAG_CHECK)) // ABC has not been removed yet.
1032  {
1033  if (accessCounts[array][value.variable()] == 0)
1034  {
1035  smallestConstants[array][value.variable()] = value.constant();
1036  biggestConstants[array][value.variable()] = value.constant();
1037  }
1038  else
1039  {
1040  // update smallest constant
1041  if (value.constant() < smallestConstants[array][value.variable()])
1042  smallestConstants[array][value.variable()] = value.constant();
1043 
1044  // update biggest constant
1045  if (value.constant() > biggestConstants[array][value.variable()])
1046  biggestConstants[array][value.variable()] = value.constant();
1047  }
1048 
1049  ++accessCounts[array][value.variable()];
1050 
1051  instructionArrayMap[i] = array;
1052  instructionIndexMap[i] = value.variable();
1053  }
1054  break;
1055  }
1056  default:
1057  if (instruction_has_dst(instr))
1058  {
1059  values[instr->dst.varindex] = Value::newUnknown();
1060  }
1061  }
1062  }
1063 
1064  // find most used array/index combination
1065  s4 bestCount = 0;
1066  s4 bestArray = 0;
1067  s4 bestIndex = 0;
1068  for (size_t array = 0; array < accessCounts.size(); array++)
1069  {
1070  if (!values[array].isUnknown()) // Is array invariant?
1071  {
1072  DynamicVector<s4> row = accessCounts[array];
1073  for (size_t index = 0; index < row.size(); index++)
1074  {
1075  s4 count = row[index];
1076  if (count > bestCount)
1077  {
1078  bestCount = count;
1079  bestArray = array;
1080  bestIndex = index;
1081  }
1082  }
1083  }
1084  }
1085 
1086  s4 smallestConstant = smallestConstants[bestArray][bestIndex];
1087  s4 biggestConstant = biggestConstants[bestArray][bestIndex];
1088 
1089  if (bestCount > 3 &&
1090  smallestConstant > std::numeric_limits<s4>::min() && // prevent overflow
1091  biggestConstant >= 0) // prevent overflow
1092  {
1093  basicblock* safeBlock = duplicateBasicblock(block);
1094 
1095  // Remove checks in block.
1096  for (s4 i = 0; i < block->icount; i++)
1097  {
1098  if (instructionArrayMap[i] == bestArray && instructionIndexMap[i] == bestIndex)
1099  {
1100  block->iinstr[i].flags.bits &= ~INS_FLAG_CHECK;
1101  }
1102  }
1103 
1104  instruction* instr;
1105 
1106  // Create first check: if (bestIndex < -1 * smallestConstant) goto safeBlock
1107  basicblock* lowerBoundsCheck = createBasicblock(jd, 2);
1108  instr = lowerBoundsCheck->iinstr;
1109  opcode_ILOAD(instr++, bestIndex, bestIndex);
1110  opcode_IFLT(instr++, bestIndex, -smallestConstant, safeBlock);
1111  assert(instr - lowerBoundsCheck->iinstr == lowerBoundsCheck->icount);
1112 
1113  // Create second check: if (bestArray == null) goto safeBlock
1114  basicblock* nullCheck = createBasicblock(jd, 2);
1115  instr = nullCheck->iinstr;
1116  opcode_ALOAD(instr++, bestArray, bestArray);
1117  opcode_IFNULL(instr++, bestArray, safeBlock);
1118  assert(instr - nullCheck->iinstr == nullCheck->icount);
1119 
1120  // Create third check: if (bestIndex >= bestArray.length - biggestConstant) goto safeBlock
1121  basicblock* upperBoundsCheck = createBasicblock(jd, 5);
1122  instr = upperBoundsCheck->iinstr;
1123  opcode_ILOAD(instr++, bestIndex, bestIndex);
1124  opcode_ALOAD(instr++, bestArray, bestArray);
1125  opcode_ARRAYLENGTH(instr++, bestArray, jd->ld->freeVariable);
1126  opcode_ISUBCONST(instr++, jd->ld->freeVariable, biggestConstant, jd->ld->freeVariable);
1127  opcode_IF_ICMPGE(instr++, bestIndex, jd->ld->freeVariable, safeBlock);
1128  assert(instr - upperBoundsCheck->iinstr == upperBoundsCheck->icount);
1129 
1130  // Create GOTO-Block between optimized and unoptimized basicblock.
1131  basicblock* trampoline = createTrampoline(jd, block->next);
1132 
1133  // Insert all blocks into the linked list.
1134  safeBlock->next = block->next;
1135  trampoline->next = safeBlock;
1136  block->next = trampoline;
1137  upperBoundsCheck->next = block;
1138  nullCheck->next = upperBoundsCheck;
1139  lowerBoundsCheck->next = nullCheck;
1140  if (lastBlock)
1141  lastBlock->next = lowerBoundsCheck;
1142  else
1143  jd->basicblocks = lowerBoundsCheck;
1144 
1145  // Store a pointer to the first check. Used for jump redirection.
1146  block->ld->arrayIndexCheck = lowerBoundsCheck;
1147  optimizationDone = true;
1148 
1149  // Adjust statistical data.
1150  jd->basicblockcount += 5;
1151 
1152  // Set iteration variable to the correct value.
1153  block = safeBlock;
1154  }
1155  }
1156 
1157  if (optimizationDone)
1158  {
1159  // Redirect jumps that go to a duplicated basicblock to lowerBoundsCheck.
1160  for (basicblock* block = jd->basicblocks; block; block = block->next)
1161  {
1162  for (instruction* instr = block->iinstr; instr != block->iinstr + block->icount; instr++)
1163  {
1164  switch (icmd_table[instr->opc].controlflow)
1165  {
1166  case CF_IF:
1167  case CF_GOTO:
1168  case CF_RET:
1169  if (instr->dst.block->ld->arrayIndexCheck)
1170  instr->dst.block = instr->dst.block->ld->arrayIndexCheck;
1171  break;
1172  case CF_JSR:
1173  if (instr->sx.s23.s3.jsrtarget.block->ld->arrayIndexCheck)
1174  instr->sx.s23.s3.jsrtarget.block = instr->sx.s23.s3.jsrtarget.block->ld->arrayIndexCheck;
1175  break;
1176  case CF_TABLE:
1177  {
1178  // count = (tablehigh - tablelow + 1) + 1 [default branch]
1179  s4 count = instr->sx.s23.s3.tablehigh - instr->sx.s23.s2.tablelow + 2;
1180 
1181  branch_target_t* target = instr->dst.table;
1182  while (--count >= 0)
1183  {
1184  if (target->block->ld->arrayIndexCheck)
1185  target->block = target->block->ld->arrayIndexCheck;
1186  target++;
1187  }
1188  break;
1189  }
1190  case CF_LOOKUP:
1191  {
1192  // default target
1193  if (instr->sx.s23.s3.lookupdefault.block->ld->arrayIndexCheck)
1194  instr->sx.s23.s3.lookupdefault.block = instr->sx.s23.s3.lookupdefault.block->ld->arrayIndexCheck;
1195 
1196  // other targets
1197  lookup_target_t* entry = instr->dst.lookup;
1198  s4 count = instr->sx.s23.s2.lookupcount;
1199  while (--count >= 0)
1200  {
1201  if (entry->target.block->ld->arrayIndexCheck)
1202  entry->target.block = entry->target.block->ld->arrayIndexCheck;
1203  entry++;
1204  }
1205  break;
1206  }
1207  case CF_END:
1208  case CF_NORMAL:
1209  // nothing
1210  break;
1211  }
1212  }
1213  }
1214  }
1215 }
1216 
1217 /*
1218  * These are local overrides for various environment variables in Emacs.
1219  * Please do not remove this and leave it at the end of the file, where
1220  * Emacs will automagically detect them.
1221  * ---------------------------------------------------------------------
1222  * Local variables:
1223  * mode: c++
1224  * indent-tabs-mode: t
1225  * c-basic-offset: 4
1226  * tab-width: 4
1227  * End:
1228  * vim:noexpandtab:sw=4:ts=4:
1229  */
1230 
val_operand_t val
Contains a Value-object for every variable.
Definition: ValueMap.hpp:36
std::size_t index
basicblock * block
void removePartiallyRedundantChecks(jitdata *jd)
Definition: duplicate.cpp:930
Represents a single loop.
#define CF_GOTO
Definition: icmd.hpp:376
basicblock * basicblocks
Definition: jit.hpp:141
Definition: jit.hpp:126
static bool instruction_has_dst(const instruction *iptr)
s4 constant() const
Definition: Value.hpp:89
VariableSet invariantArrays
#define CF_RET
Definition: icmd.hpp:380
State state
Definition: jit.hpp:313
basicblock * next
Definition: jit.hpp:337
Scalar lower() const
Definition: Interval.hpp:67
s4 outdepth
Definition: jit.hpp:326
MachineLoop * loop
#define CF_JSR
Definition: icmd.hpp:379
#define CF_NORMAL
Definition: icmd.hpp:370
s4 mpc
Definition: jit.hpp:345
int32_t varindex
Definition: instruction.hpp:63
std::set< s4 >::iterator begin()
Definition: VariableSet.hpp:49
s4 vartop
Definition: jit.hpp:149
static s4 min()
Definition: Scalar.hpp:47
#define CF_TABLE
Definition: icmd.hpp:377
#define CF_END
Definition: icmd.hpp:375
bool contains(s4 variableIndex)
Definition: VariableSet.hpp:47
Type type
Definition: reg.hpp:44
bool isUnknown() const
Definition: Value.hpp:94
lookup_target_t * lookup
instruction * iinstr
Definition: jit.hpp:319
size_t size() const
#define VAR(i)
Definition: jit.hpp:252
Definition: reg.hpp:43
s4 icount
Definition: jit.hpp:318
static bool var_is_local(const jitdata *jd, s4 i)
Definition: jit.hpp:254
s4 varcount
Definition: jit.hpp:151
Scalar upper() const
Definition: Interval.hpp:70
BeginInst *& block
LoopContainer * parent
branch_target_t target
Definition: instruction.hpp:57
dst_operand_t dst
flags_operand_t flags
#define min(a, b)
Definition: lsra.hpp:79
static s4 max()
Definition: Scalar.hpp:48
#define CF_IF
Definition: icmd.hpp:371
s4 indepth
Definition: jit.hpp:325
s4 variable() const
Definition: Value.hpp:83
MIIterator i
int32_t s4
Definition: types.hpp:45
union instruction::@12 sx
#define IS_INT_TYPE(a)
Definition: global.hpp:134
static Value newUnknown()
Definition: Value.hpp:78
#define CF_LOOKUP
Definition: icmd.hpp:378
int32_t varindex
std::vector< basicblock * > footers
icmdtable_entry_t icmd_table[256]
Definition: icmd.cpp:60
s1_operand_t s1
basicblock * block
Definition: instruction.hpp:50
int32_t controlflow
Definition: icmd.hpp:396
struct BasicblockLoopData BasicblockLoopData
Definition: loop.hpp:30
bool findFreeVariable(jitdata *jd)
Definition: duplicate.cpp:914
void resize(size_t size)
Interval counterInterval
NumericInstruction instruction() const
Definition: Scalar.hpp:87
Represents the result of the addition of a certain IR-variable with a certain constant.
Definition: Value.hpp:36
methodinfo * m
Definition: jit.hpp:127
std::vector< basicblock * > nodes
static bool var_is_temp(const jitdata *jd, s4 i)
Definition: jit.hpp:273
std::set< s4 >::iterator end()
Definition: VariableSet.hpp:50
methodinfo * method
Definition: jit.hpp:342
s4 basicblockcount
Definition: jit.hpp:144
struct instruction::@12::@13 s23
BeginInst * target
std::vector< LoopContainer * > children
s4 lower() const
Definition: Scalar.hpp:89
void groupArrayBoundsChecks(jitdata *jd)
Definition: duplicate.cpp:938
branch_target_t * table
basicblock * header
s4 constant() const
Definition: Scalar.hpp:86