001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.compilers.opt.controlflow;
014    
015    import static org.jikesrvm.compilers.opt.ir.Operators.ARCH_INDEPENDENT_END_opcode;
016    import static org.jikesrvm.compilers.opt.ir.Operators.INT_ADD_opcode;
017    import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP_opcode;
018    import static org.jikesrvm.compilers.opt.ir.Operators.INT_SUB_opcode;
019    import static org.jikesrvm.compilers.opt.ir.Operators.LABEL;
020    
021    import java.util.ArrayList;
022    import java.util.Enumeration;
023    
024    import org.jikesrvm.VM;
025    import org.jikesrvm.compilers.opt.DefUse;
026    import org.jikesrvm.compilers.opt.OptimizingCompilerException;
027    import org.jikesrvm.compilers.opt.ir.BasicBlock;
028    import org.jikesrvm.compilers.opt.ir.Binary;
029    import org.jikesrvm.compilers.opt.ir.BoundsCheck;
030    import org.jikesrvm.compilers.opt.ir.GuardResultCarrier;
031    import org.jikesrvm.compilers.opt.ir.GuardedBinary;
032    import org.jikesrvm.compilers.opt.ir.GuardedUnary;
033    import org.jikesrvm.compilers.opt.ir.IR;
034    import org.jikesrvm.compilers.opt.ir.IREnumeration;
035    import org.jikesrvm.compilers.opt.ir.IfCmp;
036    import org.jikesrvm.compilers.opt.ir.Instruction;
037    import org.jikesrvm.compilers.opt.ir.InstructionFormat;
038    import org.jikesrvm.compilers.opt.ir.Label;
039    import org.jikesrvm.compilers.opt.ir.Move;
040    import org.jikesrvm.compilers.opt.ir.NullCheck;
041    import org.jikesrvm.compilers.opt.ir.Operator;
042    import org.jikesrvm.compilers.opt.ir.Phi;
043    import org.jikesrvm.compilers.opt.ir.ResultCarrier;
044    import org.jikesrvm.compilers.opt.ir.Unary;
045    import org.jikesrvm.compilers.opt.ir.operand.BasicBlockOperand;
046    import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand;
047    import org.jikesrvm.compilers.opt.ir.operand.ConstantOperand;
048    import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
049    import org.jikesrvm.compilers.opt.ir.operand.Operand;
050    import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
051    import org.jikesrvm.compilers.opt.ssa.GCP;
052    import org.jikesrvm.compilers.opt.util.GraphNode;
053    import org.jikesrvm.util.BitVector;
054    
055    /**
056     * <p>A node in the LST (Loop Structure Tree) with added information
057     * on:
058     *
059     * <ul><li>Whether this is a countable, affine or non-regular loop</li>
060     *     <li>The registers being used to hold the loop iterator</li>
061     *     <li>The initial loop iterator value</li>
062     *     <li>The terminal loop iterator value</li>
063     *     <li>The instruction that modifies the iterator</li>
064     *     <li>The phi instruction that merges the redefined iterator with its original value</li>
065     *     <li>The condition used to test for loop termination</li>
066     *     <li>The stride operand</li>
067     * </ul>
068     *
069     * The information is only held on regular loops. The regular loop
070     * structure is:
071     *
072     * <listing>
073     * predecessor:
074     *   initialLoopIterator = ...;
075     * header:
076     *   phiLoopIterator = phi (initialLoopIterator, carriedLoopIterator)
077     *   ...body1...
078     *   carriedLoopIterator = phiLoopIterator iteratorInstr.opcode stride;
079     *   ...body2...
080     * exit:
081     *   if carriedLoopIterator condition terminalIteratorValue goto header
082     * successor:
083     * </listing>
084     *
085     * While loops (and implicitly for loops) aren't handled as they can
086     * be transformed to this form by {@link CFGTransformations}.
087     *
088     * TODO:
089     * <ul><li>More complex iterator instructions (sequences rather than single instructions)</li>
090     *     <li>Handle longs, floats and doubles as loop iterators</li>
091     *     <li>Consideration of more loop structures</li>
092     * </ul>
093     * </p>
094     *
095     * @see LSTNode
096     */
097    public final class AnnotatedLSTNode extends LSTNode {
098      // -oO Debug information Oo-
099      /**
100       * Flag to optionally print verbose debugging messages
101       */
102      private static final boolean DEBUG = false;
103    
104      // -oO Cached values for convenience Oo-
105      /**
106       * A pointer to the governing IR
107       */
108      private final IR ir;
109    
110      // -oO Blocks that get set up during the recognition of the loop Oo-
111      /**
112       * The out of loop block before the header
113       */
114      public BasicBlock predecessor;
115      // N.B. the header is defined in the superclass
116      /**
117       * The in loop block that either loops or leaves the loop
118       */
119      public BasicBlock exit;
120      /**
121       * The out of loop block following the exit block
122       */
123      public BasicBlock successor;
124    
125      // -oO Instructions that get set up during the recognition of the loop Oo-
126      /**
127       * The if instruction within the exit block
128       */
129      private Instruction ifCmpInstr;
130      /**
131       * The instruction that modifies the iterator
132       */
133      private Instruction iteratorInstr;
134    
135      // Values that get determined during the recognition of the loop
136      /**
137       * The the initial iterator that comes into the phi node in the header
138       */
139      public Operand initialIteratorValue;
140      /**
141       * The iterator that is used to loop within the exit block
142       */
143      private Operand carriedLoopIterator;
144      /**
145       * The the phi iterator that gets modified by the stride to produce the carried iterator
146       */
147      private Operand phiLoopIterator;
148      /**
149       * The value that ends the loop
150       */
151      public Operand terminalIteratorValue;
152      /**
153       * The condition that is used to check for the end of loop
154       */
155      public ConditionOperand condition;
156      /**
157       * The stride operand to the iterator instruction
158       */
159      public Operand strideValue;
160    
161      // -oO Interfaces to the rest of the compiler Oo-
162      /**
163       * Constructor
164       *
165       * @param ir   The containing IR
166       * @param node The node that's being annotated
167       */
168      public AnnotatedLSTNode(IR ir, LSTNode node) {
169        // Clone information from non-annotated node
170        super(node);
171        this.ir = ir;
172    
173        // Process inner loops
174        Enumeration<GraphNode> innerLoops = node.outNodes();
175        // Iterate over loops contained within this loop annotating from the inside out
176        while (innerLoops.hasMoreElements()) {
177          AnnotatedLSTNode nestedLoop = new AnnotatedLSTNode(ir, (LSTNode) innerLoops.nextElement());
178          insertOut(nestedLoop);
179        }
180        // Annotate node
181        perform();
182      }
183    
184      /**
185       * Is this a countable loop of the form:
186       * <listing>
187       * predecessor:
188       *   initialLoopIterator = ConstantInitialValue;
189       * header:
190       *   phiLoopIterator = phi (initialLoopIterator, carriedLoopIterator)
191       *   ...body1...
192       *   carriedLoopIterator = phiLoopIterator (+|-) ConstantStride;
193       *   ...body2...
194       * exit:
195       *   if carriedLoopIterator condition ConstantTerminalIteratorValue goto header
196       * successor:
197       * </listing>
198       * ie. lots of constant fields so we can calculate the number of
199       * loop iterations (handy for pre-scheduling).
200       *
201       * @return Whether this a countable loop or not
202       */
203      public boolean isCountableLoop() {
204        return (initialIteratorValue != null) &&
205               isConstant(initialIteratorValue) &&
206               (terminalIteratorValue != null) &&
207               isConstant(terminalIteratorValue) &&
208               (strideValue != null) &&
209               isConstant(strideValue) &&
210               (iteratorInstr != null) &&
211               ((iteratorInstr.operator.opcode == INT_ADD_opcode) || (iteratorInstr.operator.opcode == INT_SUB_opcode));
212      }
213    
214      /**
215       * Is this an affine loop of the form:
216       * <listing>
217       * predecessor:
218       *   initialLoopIterator = ...;
219       * header:
220       *   phiLoopIterator = phi (initialLoopIterator, carriedLoopIterator)
221       *   ...body1...
222       *   carriedLoopIterator = phiLoopIterator (+|-) invariantStride;
223       *   ...body2...
224       * exit:
225       *   if carriedLoopIterator condition invariantTerminalIteratorValue goto header
226       * successor:
227       * </listing>
228       * ie. lots of constant fields so we can calculate the number of
229       * loop iterations (handy for pre-scheduling).
230       *
231       * @return Whether this an affine loop or not
232       */
233      public boolean isAffineLoop() {
234        return (initialIteratorValue != null) &&
235               isLoopInvariant(initialIteratorValue, loop, header) &&
236               (terminalIteratorValue != null) &&
237               isLoopInvariant(terminalIteratorValue, loop, header) &&
238               (strideValue != null) &&
239               isLoopInvariant(strideValue, loop, header) &&
240               (iteratorInstr != null) &&
241               ((iteratorInstr.operator.opcode == INT_ADD_opcode) || (iteratorInstr.operator.opcode == INT_SUB_opcode));
242      }
243    
244      /**
245       * Is this loop a non-regular loop?
246       *
247       * @return Whether this is a non-regular loop
248       */
249      public boolean isNonRegularLoop() {
250        return !isAffineLoop();
251      }
252    
253      /**
254       * Is this value modified by the loop?
255       *
256       * @return whether the value is modified
257       */
258      public boolean isInvariant(Operand op) {
259        return isLoopInvariant(op, loop, header);
260      }
261    
262      /**
263       * Is this operand related to the iterator of this loop?
264       *
265       * @param  op Operand to test
266       * @return whether related to iterator (initial, phi or carried)
267       */
268      public boolean isRelatedToIterator(Operand op) {
269        return isFixedDistanceFromPhiIterator(op);
270      }
271    
272      /**
273       * Is this operand related to the phi iterator of this loop?
274       * @param op Operand to test
275       * @return whether related to iterator (phi)
276       */
277      public boolean isPhiLoopIterator(Operand op) {
278        return op.similar(phiLoopIterator);
279      }
280    
281      /**
282       * Is this operand related to the carried iterator of this loop?
283       * @param op Operand to test
284       * @return whether related to iterator (carried)
285       */
286      public boolean isCarriedLoopIterator(Operand op) {
287        return op.similar(carriedLoopIterator);
288      }
289    
290      /**
291       * Is the loop iterator monotonic?
292       */
293      public boolean isMonotonic() {
294        return isConstant(strideValue);
295      }
296    
297      /**
298       * Return the stride value for monotonic loops
299       *
300       * @return the constant stride value
301       */
302      public int getMonotonicStrideValue() {
303        if (iteratorInstr.operator.opcode == INT_SUB_opcode) {
304          return -((IntConstantOperand) strideValue).value;
305        } else if (iteratorInstr.operator.opcode == INT_ADD_opcode) {
306          return ((IntConstantOperand) strideValue).value;
307        } else {
308          throw new Error("Error reading stride value");
309        }
310      }
311    
312      /**
313       * Is the loop iterator a monotonic increasing value
314       */
315      public boolean isMonotonicIncreasing() {
316        if ((!isMonotonic()) ||
317            condition.isGREATER() ||
318            condition.isGREATER_EQUAL() ||
319            condition.isHIGHER() ||
320            condition.isHIGHER_EQUAL()) {
321          return false;
322        } else {
323          return getMonotonicStrideValue() > 0;
324        }
325      }
326    
327      /**
328       * Is the loop iterator a monotonic decreasing value
329       */
330      public boolean isMonotonicDecreasing() {
331        if ((!isMonotonic()) ||
332            condition.isLESS() ||
333            condition.isLESS_EQUAL() ||
334            condition.isLOWER() ||
335            condition.isLOWER_EQUAL()) {
336          return false;
337        } else {
338          return getMonotonicStrideValue() < 0;
339        }
340      }
341    
342      /**
343       * Does this basic block appear in the loop?
344       */
345      public boolean contains(BasicBlock block) {
346        return (block.getNumber() < loop.length()) && loop.get(block.getNumber());
347      }
348    
349      // -oO Utility methods Oo-
350      /**
351       * Converts the annotated loop to a concise string
352       */
353      @Override
354      public String toString() {
355        String ifCmpString = "??";
356        if ((ifCmpInstr != null) && (IfCmp.conforms(ifCmpInstr))) {
357          ifCmpString = IfCmp.getCond(ifCmpInstr).toString();
358        }
359        return ("// pred: " +
360                predecessor +
361                "\n" +
362                "loop : " +
363                initialIteratorValue +
364                ";\n" +
365                "head {" +
366                header +
367                "}:\n" +
368                "   " +
369                phiLoopIterator +
370                "=phi(" +
371                initialIteratorValue +
372                "," +
373                carriedLoopIterator +
374                ");\n" +
375                "   " +
376                carriedLoopIterator +
377                "=" +
378                phiLoopIterator +
379                "+" +
380                strideValue +
381                ";\n" +
382                "// blocks: " +
383                loop +
384                "\n" +
385                "exit {" +
386                exit +
387                "}:\n" +
388                "   if(" +
389                carriedLoopIterator +
390                " " +
391                ifCmpString +
392                " " +
393                terminalIteratorValue +
394                ")\n" +
395                "      goto head;\n" +
396                "// succ: " +
397                successor +
398                "\n");
399      }
400    
401      /**
402       * Dump a human readable description of the loop
403       */
404      public void dump() {
405        VM.sysWrite("********* START OF SSA LOOP DUMP in AnnotatedLSTNode FOR " + ir.method + "\n");
406        if (isNonRegularLoop()) {
407          VM.sysWrite("Non-regular");
408        } else if (isAffineLoop()) {
409          VM.sysWrite("Affine");
410        } else if (isCountableLoop()) {
411          VM.sysWrite("Countable");
412        } else {
413          VM.sysWrite("INVALID");
414        }
415        VM.sysWrite(" Loop:\n\tIteratorInstr: " +
416                    iteratorInstr.toString() +
417                    "\n\tIfCmpInstr:" +
418                    ifCmpInstr.toString() +
419                    "\n\tTerminalIteratorValue: " +
420                    terminalIteratorValue.toString() +
421                    "\n\tInitialIteratorValue: " +
422                    initialIteratorValue.toString() +
423                    "\n\tCarriedLoopIterator: " +
424                    carriedLoopIterator.toString() +
425                    "\n\tPhiLoopIterator: " +
426                    phiLoopIterator.toString() +
427                    "\n\tStrideValue: " +
428                    strideValue.toString() +
429                    "\n\tLoop: " +
430                    getBasicBlocks().toString() +
431                    " / " +
432                    loop.toString() +
433                    "\n");
434    
435        Enumeration<BasicBlock> loopBlocks = getBasicBlocks();
436        // loop_over_basic_blocks:
437        while (loopBlocks.hasMoreElements()) {
438          // The current basic block
439          BasicBlock curLoopBB = loopBlocks.nextElement();
440          dumpBlock(curLoopBB);
441        }
442        VM.sysWrite("*********   END OF SSA LOOP DUMP in AnnotatedLSTNode FOR " + ir.method + "\n");
443      }
444    
445      /**
446       * Dump a human readable description of a basic block within the loop
447       *
448       * @param block The basic block to dump
449       */
450      void dumpBlock(BasicBlock block) {
451        if (block == header) {
452          VM.sysWrite("Header ");
453        }
454        if (block == exit) {
455          VM.sysWrite("Exit ");
456        }
457        VM.sysWrite("Block #" + block.getNumber() + ":\n");
458        // Print the instructions
459        IREnumeration.AllInstructionsEnum instructions = new IREnumeration.AllInstructionsEnum(ir, block);
460        while (instructions.hasMoreElements()) {
461          Instruction instr = instructions.nextElement();
462          dumpInstruction(ir, instr);
463        }
464      }
465    
466      /**
467       * Dump a human readable description of an instruction within a
468       * basic block within the loop
469       *
470       * @param ir    Containing IR
471       * @param instr The instruction to dump
472       */
473      static void dumpInstruction(IR ir, Instruction instr) {
474        VM.sysWrite(instructionToString(ir, instr));
475      }
476    
477      /**
478       * Convert instruction to String in of AnnotatedLSTNode format
479       *
480       * @param ir    Containing IR
481       * @param instr The instruction to dump
482       */
483      static String instructionToString(IR ir, Instruction instr) {
484        StringBuilder sb = new StringBuilder();
485        sb.append(instr.bcIndex).append("\t").append(instr.isPEI() ? "E" : " ").append(instr.isGCPoint() ? "G " : "  ");
486        if (instr.operator == LABEL) {
487          sb.append("LABEL").append(Label.getBlock(instr).block.getNumber());
488          if (Label.getBlock(instr).block.getInfrequent()) {
489            sb.append(" (Infrequent)");
490          }
491        } else {
492          IREnumeration.AllDefsEnum defs = new IREnumeration.AllDefsEnum(ir, instr);
493          IREnumeration.AllUsesEnum uses = new IREnumeration.AllUsesEnum(ir, instr);
494          sb.append(instr.operator).append("\n\t     defs: ");
495          while (defs.hasMoreElements()) {
496            sb.append(defs.nextElement().toString());
497            if (defs.hasMoreElements()) {
498              sb.append(", ");
499            }
500          }
501          sb.append("\n\t     uses: ");
502          while (uses.hasMoreElements()) {
503            sb.append(uses.nextElement().toString());
504            if (uses.hasMoreElements()) {
505              sb.append(", ");
506            }
507          }
508        }
509        sb.append("\n");
510        return sb.toString();
511      }
512    
513      /**
514       * Test whether the operand is constant
515       *
516       * @param op Operand to determine whether it's constant
517       * @return Is the operand constant
518       */
519      static boolean isConstant(Operand op) {
520        return op instanceof IntConstantOperand;
521      }
522    
523      /**
524       * Is this operand a fixed distance from the phi iterator?
525       *
526       * @param op the operand to test
527       * @return whether or not it is a fixed distance
528       */
529      boolean isFixedDistanceFromPhiIterator(Operand op) {
530        if (op.similar(phiLoopIterator)) {
531          return true;
532        } else {
533          Instruction opInstr = definingInstruction(op);
534          if ((opInstr.operator.opcode == INT_ADD_opcode) || (opInstr.operator.opcode == INT_SUB_opcode)) {
535            Operand val1 = Binary.getVal1(opInstr);
536            Operand val2 = Binary.getVal2(opInstr);
537            return ((val1.isConstant() && isFixedDistanceFromPhiIterator(val2)) ||
538                    (val2.isConstant() && isFixedDistanceFromPhiIterator(val1)));
539          } else {
540            return false;
541          }
542        }
543      }
544    
545      /**
546       * Get fixed distance from the phi iterator
547       *
548       * @param op the operand to test
549       * @return the fixed distance
550       */
551      public int getFixedDistanceFromPhiIterator(Operand op) {
552        if (op.similar(phiLoopIterator)) {
553          return 0;
554        } else {
555          Instruction opInstr = definingInstruction(op);
556          if (opInstr.operator.opcode == INT_ADD_opcode) {
557            Operand val1 = Binary.getVal1(opInstr);
558            Operand val2 = Binary.getVal2(opInstr);
559            if (val1.isConstant()) {
560              return val1.asIntConstant().value + getFixedDistanceFromPhiIterator(val2);
561            } else {
562              if (VM.VerifyAssertions) VM._assert(val2.isConstant());
563              return getFixedDistanceFromPhiIterator(val1) + val2.asIntConstant().value;
564            }
565          } else if (opInstr.operator.opcode == INT_SUB_opcode) {
566            Operand val1 = Binary.getVal1(opInstr);
567            Operand val2 = Binary.getVal2(opInstr);
568            if (val1.isConstant()) {
569              return val1.asIntConstant().value - getFixedDistanceFromPhiIterator(val2);
570            } else {
571              if (VM.VerifyAssertions) VM._assert(val2.isConstant());
572              return getFixedDistanceFromPhiIterator(val1) - val2.asIntConstant().value;
573            }
574          }
575        }
576        throw new Error("Value isn't fixed distance from phi iterator");
577      }
578    
579      /**
580       * Test whether operand value will be invariant in a loop by tracing
581       * back earlier definitions.  There is similar code in {@link
582       * LoopUnrolling}.
583       *
584       * @param op     Operand to determine whether it's invariant
585       * @param loop   Loop in which we wish to know the invariance of the operand
586       * @param header The loop header for determining if PEIs are invariant
587       * @return Whether the operand is invariant or not
588       */
589      private static boolean isLoopInvariant(Operand op, BitVector loop, BasicBlock header) {
590        boolean result;
591        if (op.isConstant()) {
592          result = true;
593        } else if (op.isRegister()) {
594          Instruction instr = definingInstruction(op);
595          // Is the instruction that defined this register in the loop?
596          if (!CFGTransformations.inLoop(instr.getBasicBlock(), loop)) {
597            // No => the value is invariant in the loop
598            result = true;
599          } else {
600            // Trace op to where invariant/variant values may be defined
601            switch (instr.operator().format) {
602              case InstructionFormat.Binary_format:
603                result =
604                    (isLoopInvariant(Binary.getVal1(instr), loop, header) &&
605                     isLoopInvariant(Binary.getVal2(instr), loop, header));
606                break;
607              case InstructionFormat.BoundsCheck_format:
608                if (isLoopInvariant(BoundsCheck.getRef(instr), loop, header) &&
609                    isLoopInvariant(BoundsCheck.getIndex(instr), loop, header)) {
610                  // Iterate over instructions before the null check
611                  Instruction lastInst;
612                  if (header == instr.getBasicBlock()) {
613                    lastInst = instr;
614                  } else {
615                    lastInst = header.lastInstruction();
616                  }
617                  result = false;
618                  Instruction itrInst;
619                  for (itrInst = header.firstRealInstruction(); itrInst != lastInst; itrInst =
620                      itrInst.nextInstructionInCodeOrder()) {
621                    // Check it would be safe for this nullcheck to before
622                    // the loop header without changing the exception
623                    // semantics
624                    if (BoundsCheck.conforms(itrInst) &&
625                        BoundsCheck.getRef(itrInst).similar(BoundsCheck.getRef(instr)) &&
626                        BoundsCheck.getIndex(itrInst).similar(BoundsCheck.getIndex(instr))) {
627                      // it's safe if there's already an equivalent null check
628                      result = true;
629                      break;
630                    } else if (itrInst.isAllocation() ||
631                               itrInst.isDynamicLinkingPoint() ||
632                               (itrInst.operator.opcode >= ARCH_INDEPENDENT_END_opcode) ||
633                               itrInst.isPEI() ||
634                               itrInst.isThrow() ||
635                               itrInst.isImplicitLoad() ||
636                               itrInst.isImplicitStore() ||
637                               GCP.usesOrDefsPhysicalRegisterOrAddressType(itrInst)) {
638                      // it's not safe in these circumstances (see LICM)
639                      if (DEBUG) {
640                        VM.sysWriteln("null check not invariant: " + itrInst);
641                      }
642                      break;
643                    }
644                  }
645                  if (itrInst == instr) {
646                    // did we iterate to the end of the instructions and
647                    // find instr
648                    result = true;
649                  }
650                } else {
651                  result = false;
652                }
653                break;
654              case InstructionFormat.GuardedBinary_format:
655                result =
656                    (isLoopInvariant(GuardedBinary.getVal1(instr), loop, header) &&
657                     isLoopInvariant(GuardedBinary.getVal2(instr), loop, header) &&
658                     isLoopInvariant(GuardedBinary.getGuard(instr), loop, header));
659                break;
660              case InstructionFormat.GuardedUnary_format:
661                result =
662                    (isLoopInvariant(GuardedUnary.getVal(instr), loop, header) &&
663                     isLoopInvariant(GuardedUnary.getGuard(instr), loop, header));
664                break;
665              case InstructionFormat.Move_format:
666                result = isLoopInvariant(Move.getVal(instr), loop, header);
667                break;
668              case InstructionFormat.NullCheck_format:
669                if (isLoopInvariant(NullCheck.getRef(instr), loop, header)) {
670                  // Iterate over instructions before the null check
671                  Instruction lastInst;
672                  if (header == instr.getBasicBlock()) {
673                    lastInst = instr;
674                  } else {
675                    lastInst = header.lastInstruction();
676                  }
677                  result = false;
678                  Instruction itrInst;
679                  for (itrInst = header.firstRealInstruction(); itrInst != lastInst; itrInst =
680                      itrInst.nextInstructionInCodeOrder()) {
681                    // Check it would be safe for this nullcheck to before
682                    // the loop header without changing the exception
683                    // semantics
684                    if (NullCheck.conforms(itrInst) && NullCheck.getRef(itrInst).similar(NullCheck.getRef(instr))) {
685                      // it's safe if there's already an equivalent null check
686                      result = true;
687                      break;
688                    } else if (itrInst.isAllocation() ||
689                               itrInst.isDynamicLinkingPoint() ||
690                               (itrInst.operator.opcode >= ARCH_INDEPENDENT_END_opcode) ||
691                               itrInst.isPEI() ||
692                               itrInst.isThrow() ||
693                               itrInst.isImplicitLoad() ||
694                               itrInst.isImplicitStore() ||
695                               GCP.usesOrDefsPhysicalRegisterOrAddressType(itrInst)) {
696                      // it's not safe in these circumstances (see LICM)
697                      if (DEBUG) {
698                        VM.sysWriteln("null check not invariant: " + itrInst);
699                      }
700                      break;
701                    }
702                  }
703                  if (itrInst == instr) {
704                    // did we iterate to the end of the instructions and
705                    // find instr
706                    result = true;
707                  }
708                } else {
709                  result = false;
710                }
711                break;
712              case InstructionFormat.Unary_format:
713                result = isLoopInvariant(Unary.getVal(instr), loop, header);
714                break;
715              default:
716                // Unknown instruction format so leave
717                result = false;
718                break;
719            }
720          }
721        } else { // Other operand types
722          result = false;
723        }
724        if (DEBUG) {
725          VM.sysWriteln("isLoopInvariant: " + op + (result ? " true" : " false"));
726        }
727        return result;
728      }
729    
730      /**
731       * Loop invariants may not be accessible before a loop, so generate
732       * the instructions so they are
733       *
734       * @param block to generate instructions into
735       * @param op the operand we hope to use before the loop
736       */
737      public Operand generateLoopInvariantOperand(BasicBlock block, Operand op) {
738        Instruction instr = definingInstruction(op);
739        if (op.isConstant() || !CFGTransformations.inLoop(instr.getBasicBlock(), loop)) {
740          // the operand is already invariant
741          return op;
742        } else {
743          RegisterOperand result;
744          Instruction opInstr = definingInstruction(op);
745          // create result of correct type
746          if (ResultCarrier.conforms(opInstr)) {
747            result = ResultCarrier.getResult(opInstr).copyRO();
748            result.setRegister(ir.regpool.getReg(result));
749          } else {
750            if (VM.VerifyAssertions) VM._assert(GuardResultCarrier.conforms(opInstr));
751            result = GuardResultCarrier.getGuardResult(opInstr).copyRO();
752            result.setRegister(ir.regpool.getReg(result));
753          }
754          Instruction resultInstruction;
755          Operator operator = instr.operator;
756          switch (operator.format) {
757            case InstructionFormat.Binary_format:
758              resultInstruction =
759                  Binary.create(operator,
760                                result,
761                                generateLoopInvariantOperand(block, Binary.getVal1(instr)),
762                                generateLoopInvariantOperand(block, Binary.getVal2(instr)));
763              break;
764            case InstructionFormat.BoundsCheck_format:
765              resultInstruction =
766                  BoundsCheck.create(operator,
767                                     result,
768                                     generateLoopInvariantOperand(block, BoundsCheck.getRef(instr)),
769                                     generateLoopInvariantOperand(block, BoundsCheck.getIndex(instr)),
770                                     generateLoopInvariantOperand(block, BoundsCheck.getGuard(instr)));
771              break;
772            case InstructionFormat.GuardedBinary_format:
773              resultInstruction =
774                  GuardedBinary.create(operator,
775                                       result,
776                                       generateLoopInvariantOperand(block, GuardedBinary.getVal1(instr)),
777                                       generateLoopInvariantOperand(block, GuardedBinary.getVal2(instr)),
778                                       generateLoopInvariantOperand(block, GuardedBinary.getGuard(instr)));
779              break;
780            case InstructionFormat.GuardedUnary_format:
781              resultInstruction =
782                  GuardedUnary.create(operator,
783                                      result,
784                                      generateLoopInvariantOperand(block, GuardedUnary.getVal(instr)),
785                                      generateLoopInvariantOperand(block, GuardedUnary.getGuard(instr)));
786              break;
787            case InstructionFormat.Move_format:
788              resultInstruction = Move.create(operator, result, generateLoopInvariantOperand(block, Move.getVal(instr)));
789              break;
790            case InstructionFormat.NullCheck_format:
791              resultInstruction =
792                  NullCheck.create(operator, result, generateLoopInvariantOperand(block, NullCheck.getRef(instr)));
793              break;
794            case InstructionFormat.Unary_format:
795              resultInstruction = Unary.create(operator, result, generateLoopInvariantOperand(block, Unary.getVal(instr)));
796              break;
797            default:
798              // Unknown instruction format so leave
799              throw new Error("TODO: generate loop invariant for operator " + operator);
800          }
801          resultInstruction.copyPosition(instr);
802          block.appendInstruction(resultInstruction);
803          DefUse.updateDUForNewInstruction(resultInstruction);
804          return result.copyRO();
805        }
806      }
807    
808      /**
809       * Follow the operand's definition filtering out moves
810       * This code is taken and modified from an old {@link LoopUnrolling}
811       *
812       * @param use Operand to follow
813       * @return the first defintion of the instruction which isn't a move
814       */
815      public static Operand follow(Operand use) {
816        while (true) {
817          // Are we still looking at a register operand?
818          if (!use.isRegister()) {
819            // No - we're no longer filtering out moves then
820            break;
821          }
822          // Get definitions of register
823          RegisterOperand rop = use.asRegister();
824          Enumeration<RegisterOperand> defs = DefUse.defs(rop.getRegister());
825          // Does register have definitions?
826          if (!defs.hasMoreElements()) {
827            // No - Register musn't be defined in this block
828            break;
829          }
830          // Get the 1st instruction that defines the register
831          use = defs.nextElement();
832          Instruction def = use.instruction;
833          // Was the instruction that defined this register a move?
834          if (!Move.conforms(def)) {
835            // No - return the register operand from the defining instruction
836            break;
837          }
838          // Does the register have multiple defintions?
839          if (defs.hasMoreElements()) {
840            // Yes - too complex to follow so let's leave
841            break;
842          }
843          use = Move.getVal(def);
844        }
845        return use;
846      }
847    
848      /**
849       * Find the instruction that defines an operand.
850       * If the operand is a register, return the instruction that defines it, else return the operands instruction
851       *
852       * @param op The operand we're searching for the definition of
853       */
854      public static Instruction definingInstruction(Operand op) {
855        Instruction result = op.instruction;
856        // Is operand a register?
857        if (op instanceof RegisterOperand) {
858          // Yes - check the definitions out
859          Enumeration<RegisterOperand> defs = DefUse.defs(((RegisterOperand) op).getRegister());
860          // Does this register have any defintions?
861          if (!defs.hasMoreElements()) {
862            // No - must have been defined in previous block so just return register
863          } else {
864            // Get the instruction that defines the register
865            result = defs.nextElement().instruction;
866            // Check to see if there are any more definitions
867            if (defs.hasMoreElements()) {
868              // Multiple definitions of register, just return register to be safe
869              result = op.instruction;
870            }
871          }
872        }
873        return result;
874      }
875    
876      /**
877       * Is the a particular block in this loop?
878       *
879       * @return {@code true} iff block is in the loop
880       */
881      public boolean isInLoop(BasicBlock block) {
882        return CFGTransformations.inLoop(block, loop);
883      }
884    
885      /**
886       * Return an enumeration of basic blocks corresponding to a depth
887       * first traversal of the blocks in the loops graphs
888       *
889       * @param block block to visit
890       * @param bbs enumeration so far
891       * @param blocksLeftToVisit blocks left to visit
892       * @return Blocks in loop with header first and exit last
893       */
894      private BBEnum getBasicBlocks(BasicBlock block, BBEnum bbs, BitVector blocksLeftToVisit) {
895        if (block != exit) {
896          bbs.add(block);
897        }
898        blocksLeftToVisit.clear(block.getNumber());
899        Enumeration<BasicBlock> successors = block.getNormalOut();
900        while (successors.hasMoreElements()) {
901          block = successors.nextElement();
902          if (blocksLeftToVisit.get(block.getNumber())) {
903            getBasicBlocks(block, bbs, blocksLeftToVisit);
904          }
905        }
906        return bbs;
907      }
908    
909      /**
910       * Return an enumeration of basic blocks corresponding to a depth
911       * first traversal of the blocks in the loops graphs
912       *
913       * @return Blocks in loop with header first and exit last
914       */
915      public Enumeration<BasicBlock> getBasicBlocks() {
916        BitVector blocksLeftToVisit = new BitVector(loop);
917        BBEnum bbs = getBasicBlocks(header, new BBEnum(), blocksLeftToVisit);
918        if (exit != null) {
919          // place the exit block at the end of the list if we've recognized one
920          bbs.add(exit);
921        }
922        return bbs;
923      }
924    
925      /**
926       * Check the edges out of a block are within the loop
927       *
928       * @param block to check
929       */
930      private void checkOutEdgesAreInLoop(BasicBlock block) throws NonRegularLoopException {
931        // The blocks (copy of) that are branched to from this block
932        Enumeration<BasicBlock> block_outEdges = block.getOut();
933        // Check that the blocks that we branch into are all inside the loop
934        // loop_over_loop_body_block_out_edges:
935        while (block_outEdges.hasMoreElements()) {
936          BasicBlock curEdgeBB = block_outEdges.nextElement();
937          // Is this block in the loop?
938          if ((!isInLoop(curEdgeBB)) && (block != exit)) {
939            // Block wasn't in the loop
940            throw new NonRegularLoopException(
941                "Parallelization giving up: edge out of block in loop to a block outside of the loop, and the block wasn't the loop exit" +
942                ((block == header) ? " (it was the header block though)" : ""));
943          }
944        } // end of loop_over_loop_body_block_out_edges
945      }
946    
947      /**
948       * Check the edges into a block are from within the loop
949       *
950       * @param block to check
951       */
952      private void checkInEdgesAreInLoop(BasicBlock block) throws NonRegularLoopException {
953        // The blocks (copy of) that branch to this block
954        Enumeration<BasicBlock> block_inEdges = block.getIn();
955        // Check that the blocks that branch into this one are all inside the loop too
956        // loop_over_loop_body_block_in_edges:
957        while (block_inEdges.hasMoreElements()) {
958          BasicBlock curEdgeBB = block_inEdges.nextElement();
959          // Is this block in the loop?
960          if ((!isInLoop(curEdgeBB)) && (block != header)) {
961            // Block wasn't in the loop
962            throw new NonRegularLoopException(
963                "Parallelization giving up: edge into a block in the loop from a block outside of the loop, and the block wasn't the loop header" +
964                ((block == exit) ? " (it was the exit block though)" : ""));
965          }
966        } // end of loop_over_loop_body_block_in_edges
967      }
968    
969      // -oO Perform annotation Oo-
970      /**
971       * Convert node into annotated format
972       */
973      private void perform() throws OptimizingCompilerException {
974        // Check we have a loop
975        if (loop == null) {
976          return;
977        }
978        // Process the header first as it's the most likely source of non-regularity
979        try {
980          processHeader();
981          // Get the basic blocks that constitute the loop
982          Enumeration<BasicBlock> loopBlocks = getBasicBlocks();
983    
984          // Loop over all blocks within this loop and calculate iterator.. information
985          // loop_over_basic_blocks:
986          while (loopBlocks.hasMoreElements()) {
987            // The current basic block
988            BasicBlock curLoopBB = loopBlocks.nextElement();
989    
990            // Is this block the loop header?
991            if (curLoopBB == header) {
992              // The header was already processed
993            } else {
994              processLoopBlock(curLoopBB);
995            }
996          }
997        } catch (NonRegularLoopException e) {
998          if (DEBUG) {
999            VM.sysWrite(e.summary() + "\n");
1000          }
1001          // Make sure this loop looks non-regular
1002          initialIteratorValue = null;
1003        }
1004        if (DEBUG && (!isNonRegularLoop())) {
1005          dump();
1006        }
1007      }
1008    
1009      /**
1010       * Process the loop header basic block
1011       */
1012      private void processHeader() throws NonRegularLoopException {
1013        // The blocks (copy of) that branch to this block
1014        Enumeration<BasicBlock> head_inEdges = header.getIn();
1015        // Loop over blocks that branch to this one
1016        // loop_over_header_in_edges:
1017        while (head_inEdges.hasMoreElements()) {
1018          BasicBlock curEdgeBB = head_inEdges.nextElement();
1019          // Is this block in the loop?
1020          if (isInLoop(curEdgeBB)) {
1021            // Yes - must be the exit block
1022            if (exit != null) {
1023              // we already have an exit block so loop structure is too
1024              // complex for us to understand
1025              throw new NonRegularLoopException(
1026                  "Multiple back edges to the header block making exit block undistinguishable.");
1027            }
1028            exit = curEdgeBB;
1029            processExit();
1030          } else {
1031            // No - this is an out of loop block going into the header
1032            if (predecessor != null) {
1033              // we already have a predecessor to the header block, more
1034              // than 1 is beyond this optimisation at the moment
1035              throw new NonRegularLoopException(
1036                  "Multiple out of loop edges into the header making predecessor block undistinguishable.");
1037            }
1038            predecessor = curEdgeBB;
1039          }
1040        } // end of loop_over_header_in_edges
1041        // If the header isn't the exit block, check it doesn't branch outside of the loop
1042        if (header != exit) {
1043          checkOutEdgesAreInLoop(header);
1044        }
1045      }
1046    
1047      /**
1048       * Process the loop exit basic block
1049       */
1050      private void processExit() throws NonRegularLoopException {
1051        // If the exit isn't the header block, check it doesn't have in edges from outside the loop
1052        if (header != exit) {
1053          checkInEdgesAreInLoop(exit);
1054        }
1055        // Check the exit block leaves the loop
1056        Enumeration<BasicBlock> exitBlock_outEdges = exit.getOut();
1057        boolean exits = false;
1058        // check_exit_block_exits:
1059        while (exitBlock_outEdges.hasMoreElements()) {
1060          BasicBlock curExitBlockOutEdgeBB = exitBlock_outEdges.nextElement();
1061          if (isInLoop(curExitBlockOutEdgeBB)) {
1062            // An in loop out edge from the exit block
1063          } else {
1064            // An out of loop edge from the exit block
1065            exits = true;
1066            successor = curExitBlockOutEdgeBB;
1067            if (successor == header) {
1068              throw new NonRegularLoopException("Unimplemented condition - see LoopUnrolling.java : 240");
1069            }
1070          }
1071        } // end of check_exit_block_exits
1072        if (!exits) {
1073          throw new NonRegularLoopException(
1074              "Exit block (containing back edge to header) doesn't have an out of loop out edge.");
1075        } else {
1076          // Get the if instruction used to loop in the exit block
1077          ifCmpInstr = exit.firstBranchInstruction();
1078          if (ifCmpInstr == null) {
1079            throw new NonRegularLoopException("Exit block branch doesn't have a (1st) branching instruction.");
1080          } else if (ifCmpInstr.operator.opcode != INT_IFCMP_opcode) {
1081            throw new NonRegularLoopException("branch is int_ifcmp but " + ifCmpInstr.operator + "\n");
1082          } else {
1083            // Get the terminal and iterator operations
1084            carriedLoopIterator = follow(IfCmp.getVal1(ifCmpInstr));
1085            terminalIteratorValue = follow(IfCmp.getVal2(ifCmpInstr));
1086            condition = (ConditionOperand) IfCmp.getCond(ifCmpInstr).copy();
1087            // Check we have them the right way around and that they do the job we expect
1088            {
1089              boolean iteratorInvariant = isLoopInvariant(carriedLoopIterator, loop, header);
1090              boolean terminalValueInvariant = isLoopInvariant(terminalIteratorValue, loop, header);
1091              // Is the iterator loop invariant?
1092              if (iteratorInvariant) {
1093                // Yes - Is the terminal value loop invariant?
1094                if (terminalValueInvariant) {
1095                  // Yes - both parameters to the condition are invariant
1096                  throw new NonRegularLoopException(
1097                      "Exit block condition values are both invariant (single or infinite loop):\n" +
1098                      "Loop = " +
1099                      loop.toString() +
1100                      "\nIterator = " +
1101                      carriedLoopIterator +
1102                      "\nTerminal = " +
1103                      terminalIteratorValue);
1104                } else {
1105                  // No - swap values over
1106                  Operand temp = terminalIteratorValue;
1107                  terminalIteratorValue = carriedLoopIterator;
1108                  carriedLoopIterator = temp;
1109                }
1110              } else {
1111                // No - Is the terminal value loop invariant?
1112                if (terminalValueInvariant) {
1113                  // Yes - this is the condition we hoped for
1114                } else {
1115                  // No - both loop values are variant and loop is too complex to analyse
1116                  throw new NonRegularLoopException("Exit block condition values are both variant.");
1117                }
1118              }
1119            }
1120            // Check target of "if" is the header
1121            if (Label.getBlock(IfCmp.getTarget(ifCmpInstr).target).block != header) {
1122              // No - can't optimise loop in this format
1123              // TODO: swap ifxxx around so that branch is to header and fall-through is exit
1124              throw new NonRegularLoopException("Target of exit block branch isn't the loop header.");
1125            }
1126            // Calculate stride value
1127            Enumeration<RegisterOperand> iteratorDefs =
1128                DefUse.defs(((RegisterOperand) carriedLoopIterator).getRegister());
1129            // Loop over definitions of the iterator operand ignoring moves
1130            while (iteratorDefs.hasMoreElements()) {
1131              Operand curDef = follow(iteratorDefs.nextElement());
1132              // Is this definition within the loop?
1133              if (isInLoop(curDef.instruction.getBasicBlock())) {
1134                // Yes - have we already got an iterator instruction
1135                if ((iteratorInstr == null) || (iteratorInstr == curDef.instruction)) {
1136                  // No - record
1137                  iteratorInstr = curDef.instruction;
1138                } else {
1139                  // Yes - loop too complex again
1140                  throw new NonRegularLoopException("Multiple definitions of the iterator.");
1141                }
1142              }
1143            }
1144            // Did we find an instruction?
1145            if (iteratorInstr == null) {
1146              // No => error
1147              throw new NonRegularLoopException("No iterator definition found.");
1148            } else
1149            if ((iteratorInstr.operator.opcode != INT_ADD_opcode) && (iteratorInstr.operator.opcode != INT_SUB_opcode)) {
1150              // Is it an instruction we recognise?
1151              // TODO: support more iterator instructions
1152              throw new NonRegularLoopException("Unrecognized iterator operator " + iteratorInstr.operator);
1153            } else {
1154              // only carry on further analysis if we think we can understand the loop
1155              // Does this iterator instruction use the same register as it defines
1156              Operand iteratorUse = follow(Binary.getVal1(iteratorInstr));
1157              // The iterator should be using a phi node of the initial and generated value
1158              if (!carriedLoopIterator.similar(iteratorUse)) {
1159                // SSA ok so far, read PHI node
1160                Instruction phiInstr = iteratorUse.instruction;
1161                if (!Phi.conforms(phiInstr)) {
1162                  // We didn't find a PHI instruction
1163                  throw new NonRegularLoopException("Iterator (" +
1164                                                    iteratorUse +
1165                                                    ") not using a phi instruction but " +
1166                                                    phiInstr);
1167                }
1168                // We have the SSA we hoped for - tidy up
1169                strideValue = follow(Binary.getVal2(iteratorInstr));
1170                initialIteratorValue = follow(Phi.getValue(phiInstr, 0));
1171                phiLoopIterator = iteratorUse;
1172                if (initialIteratorValue instanceof BasicBlockOperand) {
1173                  throw new Error("BasicBlock mess up!");
1174                }
1175                if (initialIteratorValue == iteratorUse) {
1176                  initialIteratorValue = follow(Phi.getValue(phiInstr, 1));
1177                }
1178                if (initialIteratorValue instanceof BasicBlockOperand) {
1179                  throw new Error("BasicBlock mess up!2");
1180                }
1181              } else {
1182                // Not in SSA form as iterator modifies an operand
1183                throw new NonRegularLoopException("Iterator modifies (uses and defines) operand " +
1184                                                  iteratorUse +
1185                                                  " and is therefore not in SSA form.");
1186              }
1187              // Check the initialIteratorValue was defined outside of (before) the loop header or is constant
1188              if (!isLoopInvariant(initialIteratorValue, loop, header)) {
1189                throw new NonRegularLoopException("Initial iterator not constant or defined outside the loop - " +
1190                                                  initialIteratorValue);
1191              } else if (!(strideValue instanceof ConstantOperand)) {
1192                // Check the stride value constant
1193                throw new NonRegularLoopException("Stride not constant - " + strideValue);
1194              }
1195            }
1196          }
1197        }
1198      }
1199    
1200      /**
1201       * Process a regular block within the loop
1202       *
1203       * @param block The basic block to process
1204       */
1205      private void processLoopBlock(BasicBlock block) throws NonRegularLoopException {
1206        checkInEdgesAreInLoop(block);
1207        checkOutEdgesAreInLoop(block);
1208      }
1209    
1210      /**
1211       * Get the carried loop iterator
1212       *
1213       * @return carried loop iterator
1214       */
1215      public Operand getCarriedLoopIterator() {
1216        return carriedLoopIterator;
1217      }
1218    
1219      // -oO Utility classes Oo-
1220      /**
1221       * Exception thrown when a non-regular loop is encountered
1222       */
1223      private static class NonRegularLoopException extends Exception {
1224        /** Support for exception serialization */
1225        static final long serialVersionUID = -7553504903633114882L;
1226        /**
1227         * Brief description of problem
1228         */
1229        private final String _summary;
1230    
1231        /**
1232         * Constructor
1233         */
1234        NonRegularLoopException(String s) {
1235          super(s);
1236          _summary = s;
1237        }
1238    
1239        /**
1240         * A brief description of the error
1241         */
1242        String summary() {
1243          return _summary;
1244        }
1245      }
1246    
1247      /**
1248       * This class implements an enumeration of {@link BasicBlock}s. It is
1249       * used for iterating over basic blocks in a fashion determined by
1250       * the order in which basic blocks are added.
1251       */
1252      static final class BBEnum implements Enumeration<BasicBlock> {
1253        /**
1254         * ArrayList holding basic blocks
1255         */
1256        private final ArrayList<BasicBlock> blocks;
1257        /**
1258         * The current block of the iterator
1259         */
1260        private int currentBlock;
1261    
1262        /**
1263         * Constructor
1264         */
1265        public BBEnum() {
1266          blocks = new ArrayList<BasicBlock>();
1267        }
1268    
1269        /**
1270         * Insert a block to the end of the list
1271         * @param block to insert
1272         */
1273        public void add(BasicBlock block) {
1274          blocks.add(block);
1275        }
1276    
1277        /**
1278         * Is the iterator at the end of the vector
1279         * @return whether there are more elements in the vector
1280         */
1281        @Override
1282        public boolean hasMoreElements() {
1283          return currentBlock < blocks.size();
1284        }
1285    
1286        /**
1287         * Get the next element from the vector and move the current block along
1288         * @return next element
1289         */
1290        @Override
1291        public BasicBlock nextElement() {
1292          BasicBlock result = blocks.get(currentBlock);
1293          currentBlock++;
1294          return result;
1295        }
1296    
1297        /**
1298         * String representation of the object
1299         * @return string representing the object
1300         */
1301        @Override
1302        public String toString() {
1303          return blocks.toString();
1304        }
1305      }
1306    }