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.IRTools.CPOS;
016    import static org.jikesrvm.compilers.opt.ir.Operators.BBEND;
017    import static org.jikesrvm.compilers.opt.ir.Operators.BOOLEAN_CMP_ADDR;
018    import static org.jikesrvm.compilers.opt.ir.Operators.BOOLEAN_CMP_INT;
019    import static org.jikesrvm.compilers.opt.ir.Operators.BOOLEAN_NOT;
020    import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_2FLOAT_opcode;
021    import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ADD_opcode;
022    import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_MOVE_opcode;
023    import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_MUL_opcode;
024    import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_NEG_opcode;
025    import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_SUB_opcode;
026    import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_2DOUBLE_opcode;
027    import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_ADD_opcode;
028    import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_MOVE_opcode;
029    import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_MUL_opcode;
030    import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_NEG_opcode;
031    import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_SUB_opcode;
032    import static org.jikesrvm.compilers.opt.ir.Operators.GOTO;
033    import static org.jikesrvm.compilers.opt.ir.Operators.INT_2BYTE_opcode;
034    import static org.jikesrvm.compilers.opt.ir.Operators.INT_2SHORT_opcode;
035    import static org.jikesrvm.compilers.opt.ir.Operators.INT_2USHORT_opcode;
036    import static org.jikesrvm.compilers.opt.ir.Operators.INT_ADD_opcode;
037    import static org.jikesrvm.compilers.opt.ir.Operators.INT_AND_opcode;
038    import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP;
039    import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP2;
040    import static org.jikesrvm.compilers.opt.ir.Operators.INT_MOVE;
041    import static org.jikesrvm.compilers.opt.ir.Operators.INT_MOVE_opcode;
042    import static org.jikesrvm.compilers.opt.ir.Operators.INT_MUL_opcode;
043    import static org.jikesrvm.compilers.opt.ir.Operators.INT_NEG_opcode;
044    import static org.jikesrvm.compilers.opt.ir.Operators.INT_NOT_opcode;
045    import static org.jikesrvm.compilers.opt.ir.Operators.INT_OR_opcode;
046    import static org.jikesrvm.compilers.opt.ir.Operators.INT_SHL_opcode;
047    import static org.jikesrvm.compilers.opt.ir.Operators.INT_SHR_opcode;
048    import static org.jikesrvm.compilers.opt.ir.Operators.INT_SUB_opcode;
049    import static org.jikesrvm.compilers.opt.ir.Operators.INT_USHR_opcode;
050    import static org.jikesrvm.compilers.opt.ir.Operators.INT_XOR_opcode;
051    import static org.jikesrvm.compilers.opt.ir.Operators.REF_ADD_opcode;
052    import static org.jikesrvm.compilers.opt.ir.Operators.REF_AND_opcode;
053    import static org.jikesrvm.compilers.opt.ir.Operators.REF_IFCMP;
054    import static org.jikesrvm.compilers.opt.ir.Operators.REF_MOVE_opcode;
055    import static org.jikesrvm.compilers.opt.ir.Operators.REF_NOT_opcode;
056    import static org.jikesrvm.compilers.opt.ir.Operators.REF_OR_opcode;
057    import static org.jikesrvm.compilers.opt.ir.Operators.REF_SHL_opcode;
058    import static org.jikesrvm.compilers.opt.ir.Operators.REF_SHR_opcode;
059    import static org.jikesrvm.compilers.opt.ir.Operators.REF_SUB_opcode;
060    import static org.jikesrvm.compilers.opt.ir.Operators.REF_USHR_opcode;
061    import static org.jikesrvm.compilers.opt.ir.Operators.REF_XOR_opcode;
062    import static org.jikesrvm.compilers.opt.ir.Operators.RETURN;
063    
064    import java.util.Enumeration;
065    import java.util.HashMap;
066    import java.util.HashSet;
067    
068    import org.jikesrvm.VM;
069    import org.jikesrvm.classloader.Atom;
070    import org.jikesrvm.classloader.TypeReference;
071    import org.jikesrvm.compilers.opt.OptimizingCompilerException;
072    import org.jikesrvm.compilers.opt.ir.BasicBlock;
073    import org.jikesrvm.compilers.opt.ir.BooleanCmp;
074    import org.jikesrvm.compilers.opt.ir.CondMove;
075    import org.jikesrvm.compilers.opt.ir.Goto;
076    import org.jikesrvm.compilers.opt.ir.IR;
077    import org.jikesrvm.compilers.opt.ir.IRTools;
078    import org.jikesrvm.compilers.opt.ir.IfCmp;
079    import org.jikesrvm.compilers.opt.ir.IfCmp2;
080    import org.jikesrvm.compilers.opt.ir.InlineGuard;
081    import org.jikesrvm.compilers.opt.ir.Instruction;
082    import org.jikesrvm.compilers.opt.ir.Move;
083    import org.jikesrvm.compilers.opt.ir.Operator;
084    import org.jikesrvm.compilers.opt.ir.Register;
085    import org.jikesrvm.compilers.opt.ir.Return;
086    import org.jikesrvm.compilers.opt.ir.Unary;
087    import org.jikesrvm.compilers.opt.ir.operand.BranchOperand;
088    import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand;
089    import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand;
090    import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
091    import org.jikesrvm.compilers.opt.ir.operand.Operand;
092    import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
093    
094    /**
095     * Perform simple peephole optimizations for branches.
096     */
097    public final class BranchOptimizations extends BranchOptimizationDriver {
098    
099      /**
100       * Name of abs method used as a special case in conditional moves
101       */
102      private static final Atom ABS = Atom.findOrCreateAsciiAtom("abs");
103    
104      /**
105       * Is branch optimizations allowed to change the code order to
106       * create fallthrough edges (and thus merge basic blocks)?
107       * After we run code reordering, we disallow this transformation to avoid
108       * destroying the desired code order.
109       */
110      private final boolean mayReorderCode;
111    
112      /**
113       * Are we allowed to duplication conditional branches?
114       * Restricted until backedge yieldpoints are inserted to
115       * avoid creating irreducible control flow by duplicating
116       * a conditional branch in a loop header into a block outside the
117       * loop, thus creating two loop entry blocks.
118       */
119      private final boolean mayDuplicateCondBranches;
120    
121      /**
122       * @param level the minimum optimization level at which the branch
123       *              optimizations should be performed.
124       * @param mayReorderCode are we allowed to change the code order?
125       * @param mayDuplicateCondBranches are we allowed to duplicate conditional branches?
126       */
127      public BranchOptimizations(int level, boolean mayReorderCode, boolean mayDuplicateCondBranches) {
128        super(level, true);
129        this.mayReorderCode = mayReorderCode;
130        this.mayDuplicateCondBranches = mayDuplicateCondBranches;
131      }
132    
133      /**
134       * @param level the minimum optimization level at which the branch
135       *              optimizations should be performed.
136       * @param mayReorderCode are we allowed to change the code order?
137       * @param mayDuplicateCondBranches are we allowed to duplicate conditional branches?
138       * @param simplify simplify prior to optimizing?
139       */
140      public BranchOptimizations(int level, boolean mayReorderCode, boolean mayDuplicateCondBranches,
141                                     boolean simplify) {
142        super(level, simplify);
143        this.mayReorderCode = mayReorderCode;
144        this.mayDuplicateCondBranches = mayDuplicateCondBranches;
145      }
146    
147      /**
148       * This method actually does the work of attempting to
149       * peephole optimize a branch instruction.
150       * See Muchnick ~p.590
151       * @param ir the containing IR
152       * @param s the branch instruction to optimize
153       * @param bb the containing basic block
154       * @return {@code true} if an optimization was applied, {@code false} otherwise
155       */
156      @Override
157      protected boolean optimizeBranchInstruction(IR ir, Instruction s, BasicBlock bb) {
158        if (Goto.conforms(s)) {
159          return processGoto(ir, s, bb);
160        } else if (IfCmp.conforms(s)) {
161          return processConditionalBranch(ir, s, bb);
162        } else if (InlineGuard.conforms(s)) {
163          return processInlineGuard(ir, s, bb);
164        } else if (IfCmp2.conforms(s)) {
165          return processTwoTargetConditionalBranch(ir, s, bb);
166        } else {
167          return false;
168        }
169      }
170    
171      /**
172       * Perform optimizations for a Goto.
173       *
174       * <p> Patterns:
175       * <pre>
176       *    1)      GOTO A       replaced by  GOTO B
177       *         A: GOTO B
178       *
179       *    2)      GOTO A       replaced by  IF .. GOTO B
180       *         A: IF .. GOTO B              GOTO C
181       *         C: ...
182       *    3)   GOTO next instruction eliminated
183       *    4)      GOTO A       replaced by  GOTO B
184       *         A: LABEL
185       *            BBEND
186       *         B:
187       *    5)   GOTO BBn where BBn has exactly one in edge
188       *         - move BBn immediately after the GOTO in the code order,
189       *           so that pattern 3) will create a fallthrough
190       * <pre>
191       *
192       * <p> Precondition: Goto.conforms(g)
193       *
194       * @param ir governing IR
195       * @param g the instruction to optimize
196       * @param bb the basic block holding g
197       * @return {@code true} if made a transformation
198       */
199      private boolean processGoto(IR ir, Instruction g, BasicBlock bb) {
200        BasicBlock targetBlock = g.getBranchTarget();
201    
202        // don't optimize jumps to a code motion landing pad
203        if (targetBlock.getLandingPad()) return false;
204    
205        Instruction targetLabel = targetBlock.firstInstruction();
206        // get the first real instruction at the g target
207        // NOTE: this instruction is not necessarily in targetBlock,
208        // iff targetBlock has no real instructions
209        Instruction targetInst = firstRealInstructionFollowing(targetLabel);
210        if (targetInst == null || targetInst == g) {
211          return false;
212        }
213        Instruction nextLabel = firstLabelFollowing(g);
214        if (targetLabel == nextLabel) {
215          // found a GOTO to the next instruction.  just remove it.
216          g.remove();
217          return true;
218        }
219        if (Goto.conforms(targetInst)) {
220          // unconditional branch to unconditional branch.
221          // replace g with goto to targetInst's target
222          Instruction target2 = firstRealInstructionFollowing(targetInst.getBranchTarget().firstInstruction());
223          if (target2 == targetInst) {
224            // Avoid an infinite recursion in the following bizarre scenario:
225            // g: goto L
226            // ...
227            // L: goto L
228            // This happens in jByteMark.EmFloatPnt.denormalize() due to a while(true) {}
229            return false;
230          }
231          Goto.setTarget(g, (BranchOperand) Goto.getTarget(targetInst).copy());
232          bb.recomputeNormalOut(ir); // fix the CFG
233          return true;
234        }
235        if (targetBlock.isEmpty()) {
236          // GOTO an empty basic block.  Change target to the
237          // next block.
238          BasicBlock nextBlock = targetBlock.getFallThroughBlock();
239          Goto.setTarget(g, nextBlock.makeJumpTarget());
240          bb.recomputeNormalOut(ir); // fix the CFG
241          return true;
242        }
243        if (mayDuplicateCondBranches && IfCmp.conforms(targetInst)) {
244          // unconditional branch to a conditional branch.
245          // If the Goto is the only branch instruction in its basic block
246          // and the IfCmp is the only non-GOTO branch instruction
247          // in its basic block then replace the goto with a copy of
248          // targetInst and append another GOTO to the not-taken
249          // target of targetInst's block.
250          // We impose these additional restrictions to avoid getting
251          // multiple conditional branches in a single basic block.
252          if (!g.prevInstructionInCodeOrder().isBranch() &&
253              (targetInst.nextInstructionInCodeOrder().operator == BBEND ||
254               targetInst.nextInstructionInCodeOrder().operator == GOTO)) {
255            Instruction copy = targetInst.copyWithoutLinks();
256            g.replace(copy);
257            Instruction newGoto = targetInst.getBasicBlock().getNotTakenNextBlock().makeGOTO();
258            copy.insertAfter(newGoto);
259            bb.recomputeNormalOut(ir); // fix the CFG
260            return true;
261          }
262        }
263    
264        // try to create a fallthrough
265        if (mayReorderCode && targetBlock.getNumberOfIn() == 1) {
266          BasicBlock ftBlock = targetBlock.getFallThroughBlock();
267          if (ftBlock != null) {
268            BranchOperand ftTarget = ftBlock.makeJumpTarget();
269            targetBlock.appendInstruction(CPOS(g,Goto.create(GOTO, ftTarget)));
270          }
271    
272          ir.cfg.removeFromCodeOrder(targetBlock);
273          ir.cfg.insertAfterInCodeOrder(bb, targetBlock);
274          targetBlock.recomputeNormalOut(ir); // fix the CFG
275          return true;
276        }
277        return false;
278      }
279    
280      /**
281       * Perform optimizations for a conditional branch.
282       *
283       * <pre>
284       * 1)   IF .. GOTO A          replaced by  IF .. GOTO B
285       *      ...
286       *   A: GOTO B
287       * 2)   conditional branch to next instruction eliminated
288       * 3)   IF (condition) GOTO A  replaced by  IF (!condition) GOTO B
289       *      GOTO B                           A: ...
290       *   A: ...
291       * 4) special case to generate Boolean compare opcode
292       * 5) special case to generate conditional move sequence
293       * 6)   IF .. GOTO A       replaced by  IF .. GOTO B
294       *   A: LABEL
295       *      BBEND
296       *   B:
297       * 7)  fallthrough to a goto: replicate goto to enable other optimizations.
298       * </pre>
299       *
300       * <p> Precondition: IfCmp.conforms(cb)
301       *
302       * @param ir the governing IR
303       * @param cb the instruction to optimize
304       * @param bb the basic block holding if
305       * @return {@code true} iff made a transformation
306       */
307      private boolean processConditionalBranch(IR ir, Instruction cb, BasicBlock bb) {
308        BasicBlock targetBlock = cb.getBranchTarget();
309    
310        // don't optimize jumps to a code motion landing pad
311        if (targetBlock.getLandingPad()) return false;
312    
313        Instruction targetLabel = targetBlock.firstInstruction();
314        // get the first real instruction at the branch target
315        // NOTE: this instruction is not necessarily in targetBlock,
316        // iff targetBlock has no real instructions
317        Instruction targetInst = firstRealInstructionFollowing(targetLabel);
318        if (targetInst == null || targetInst == cb) {
319          return false;
320        }
321        boolean endsBlock = cb.nextInstructionInCodeOrder().operator() == BBEND;
322        if (endsBlock) {
323          Instruction nextLabel = firstLabelFollowing(cb);
324    
325          if (targetLabel == nextLabel) {
326            // found a conditional branch to the next instruction.  just remove it.
327            cb.remove();
328            return true;
329          }
330          Instruction nextI = firstRealInstructionFollowing(nextLabel);
331          if (nextI != null && Goto.conforms(nextI)) {
332            // Check that the target is not the fall through (the goto itself).
333            // If we add a goto to the next block, it will be removed by
334            // processGoto and we will loop indefinitely.
335            // This can be tripped by (strange) code such as:
336            // if (condition) while (true);
337            BasicBlock gotoTarget = nextI.getBranchTarget();
338            Instruction gotoLabel = gotoTarget.firstInstruction();
339            Instruction gotoInst = firstRealInstructionFollowing(gotoLabel);
340    
341            if (gotoInst != nextI) {
342              // replicate Goto
343              cb.insertAfter(nextI.copyWithoutLinks());
344              bb.recomputeNormalOut(ir); // fix the CFG
345              return true;
346            }
347          }
348        }
349        // attempt to generate boolean compare.
350        if (generateBooleanCompare(ir, bb, cb, targetBlock)) {
351          // generateBooleanCompare does all necessary CFG fixup.
352          return true;
353        }
354        // attempt to generate a sequence using conditional moves
355        if (generateCondMove(ir, bb, cb)) {
356          // generateCondMove does all necessary CFG fixup.
357          return true;
358        }
359    
360        // do we fall through to a block that has only a goto?
361        BasicBlock fallThrough = bb.getFallThroughBlock();
362        if (fallThrough != null) {
363          Instruction fallThroughInstruction = fallThrough.firstRealInstruction();
364          if ((fallThroughInstruction != null) && Goto.conforms(fallThroughInstruction)) {
365            // copy goto to bb
366            bb.appendInstruction(fallThroughInstruction.copyWithoutLinks());
367            bb.recomputeNormalOut(ir);
368          }
369        }
370    
371        if (Goto.conforms(targetInst)) {
372          // conditional branch to unconditional branch.
373          // change conditional branch target to latter's target
374          Instruction target2 = firstRealInstructionFollowing(targetInst.getBranchTarget().firstInstruction());
375          if (target2 == targetInst) {
376            // Avoid an infinite recursion in the following scenario:
377            // g: if (...) goto L
378            // ...
379            // L: goto L
380            // This happens in GCUtil in some systems due to a while(true) {}
381            return false;
382          }
383          IfCmp.setTarget(cb, (BranchOperand) Goto.getTarget(targetInst).copy());
384          bb.recomputeNormalOut(ir); // fix the CFG
385          return true;
386        }
387        if (targetBlock.isEmpty()) {
388          // branch to an empty block.  Change target to the next block.
389          BasicBlock nextBlock = targetBlock.getFallThroughBlock();
390          IfCmp.setTarget(cb, nextBlock.makeJumpTarget());
391          bb.recomputeNormalOut(ir); // fix the CFG
392          return true;
393        }
394        if (isFlipCandidate(cb, targetInst)) {
395          flipConditionalBranch(cb);
396          bb.recomputeNormalOut(ir); // fix the CFG
397          return true;
398        }
399        return false;
400      }
401    
402      /**
403       * Perform optimizations for an inline guard.
404       *
405       * <p> Precondition: InlineGuard.conforms(cb)
406       *
407       * @param ir the governing IR
408       * @param cb the instruction to optimize
409       * @param bb the basic block holding if
410       * @return {@code true} iff made a transformation
411       */
412      private boolean processInlineGuard(IR ir, Instruction cb, BasicBlock bb) {
413        BasicBlock targetBlock = cb.getBranchTarget();
414        Instruction targetLabel = targetBlock.firstInstruction();
415        // get the first real instruction at the branch target
416        // NOTE: this instruction is not necessarily in targetBlock,
417        // iff targetBlock has no real instructions
418        Instruction targetInst = firstRealInstructionFollowing(targetLabel);
419        if (targetInst == null || targetInst == cb) {
420          return false;
421        }
422        boolean endsBlock = cb.nextInstructionInCodeOrder().operator() == BBEND;
423        if (endsBlock) {
424          Instruction nextLabel = firstLabelFollowing(cb);
425          if (targetLabel == nextLabel) {
426            // found a conditional branch to the next instruction.  just remove it.
427            cb.remove();
428            return true;
429          }
430          Instruction nextI = firstRealInstructionFollowing(nextLabel);
431          if (nextI != null && Goto.conforms(nextI)) {
432            // replicate Goto
433            cb.insertAfter(nextI.copyWithoutLinks());
434            bb.recomputeNormalOut(ir); // fix the CFG
435            return true;
436          }
437        }
438        // do we fall through to a block that has only a goto?
439        BasicBlock fallThrough = bb.getFallThroughBlock();
440        if (fallThrough != null) {
441          Instruction fallThroughInstruction = fallThrough.firstRealInstruction();
442          if ((fallThroughInstruction != null) && Goto.conforms(fallThroughInstruction)) {
443            // copy goto to bb
444            bb.appendInstruction(fallThroughInstruction.copyWithoutLinks());
445            bb.recomputeNormalOut(ir);
446          }
447        }
448    
449        if (Goto.conforms(targetInst)) {
450          // conditional branch to unconditional branch.
451          // change conditional branch target to latter's target
452          InlineGuard.setTarget(cb, (BranchOperand) Goto.getTarget(targetInst).copy());
453          bb.recomputeNormalOut(ir); // fix the CFG
454          return true;
455        }
456        if (targetBlock.isEmpty()) {
457          // branch to an empty block.  Change target to the next block.
458          BasicBlock nextBlock = targetBlock.getFallThroughBlock();
459          InlineGuard.setTarget(cb, nextBlock.makeJumpTarget());
460          bb.recomputeNormalOut(ir); // fix the CFG
461          return true;
462        }
463        return false;
464      }
465    
466      /**
467       * Perform optimizations for a two way conditional branch.
468       *
469       * <p> Precondition: IfCmp2.conforms(cb)
470       *
471       * @param ir the governing IR
472       * @param cb the instruction to optimize
473       * @param bb the basic block holding if
474       * @return {@code true} iff made a transformation
475       */
476      private boolean processTwoTargetConditionalBranch(IR ir, Instruction cb, BasicBlock bb) {
477        // First condition/target
478        Instruction target1Label = IfCmp2.getTarget1(cb).target;
479        Instruction target1Inst = firstRealInstructionFollowing(target1Label);
480        Instruction nextLabel = firstLabelFollowing(cb);
481        boolean endsBlock = cb.nextInstructionInCodeOrder().operator() == BBEND;
482        if (target1Inst != null && target1Inst != cb) {
483          if (Goto.conforms(target1Inst)) {
484            // conditional branch to unconditional branch.
485            // change conditional branch target to latter's target
486            IfCmp2.setTarget1(cb, (BranchOperand) Goto.getTarget(target1Inst).copy());
487            bb.recomputeNormalOut(ir); // fix CFG
488            return true;
489          }
490          BasicBlock target1Block = target1Label.getBasicBlock();
491          if (target1Block.isEmpty()) {
492            // branch to an empty block.  Change target to the next block.
493            BasicBlock nextBlock = target1Block.getFallThroughBlock();
494            IfCmp2.setTarget1(cb, nextBlock.makeJumpTarget());
495            bb.recomputeNormalOut(ir); // fix the CFG
496            return true;
497          }
498        }
499    
500        // Second condition/target
501        Instruction target2Label = IfCmp2.getTarget2(cb).target;
502        Instruction target2Inst = firstRealInstructionFollowing(target2Label);
503        if (target2Inst != null && target2Inst != cb) {
504          if (Goto.conforms(target2Inst)) {
505            // conditional branch to unconditional branch.
506            // change conditional branch target to latter's target
507            IfCmp2.setTarget2(cb, (BranchOperand) Goto.getTarget(target2Inst).copy());
508            bb.recomputeNormalOut(ir); // fix CFG
509            return true;
510          }
511          if ((target2Label == nextLabel) && endsBlock) {
512            // found a conditional branch to the next instruction. Reduce to IfCmp
513            if (VM.VerifyAssertions) VM._assert(cb.operator() == INT_IFCMP2);
514            IfCmp.mutate(cb,
515                         INT_IFCMP,
516                         IfCmp2.getGuardResult(cb),
517                         IfCmp2.getVal1(cb),
518                         IfCmp2.getVal2(cb),
519                         IfCmp2.getCond1(cb),
520                         IfCmp2.getTarget1(cb),
521                         IfCmp2.getBranchProfile1(cb));
522            return true;
523          }
524          BasicBlock target2Block = target2Label.getBasicBlock();
525          if (target2Block.isEmpty()) {
526            // branch to an empty block.  Change target to the next block.
527            BasicBlock nextBlock = target2Block.getFallThroughBlock();
528            IfCmp2.setTarget2(cb, nextBlock.makeJumpTarget());
529            bb.recomputeNormalOut(ir); // fix the CFG
530            return true;
531          }
532        }
533    
534        // if fall through to a goto; replicate the goto
535        if (endsBlock) {
536          Instruction nextI = firstRealInstructionFollowing(nextLabel);
537          if (nextI != null && Goto.conforms(nextI)) {
538            // replicate Goto
539            cb.insertAfter(nextI.copyWithoutLinks());
540            bb.recomputeNormalOut(ir); // fix the CFG
541            return true;
542          }
543        }
544    
545        return false;
546      }
547    
548      /**
549       * Is a conditional branch a candidate to be flipped?
550       * See comment 3) of processConditionalBranch
551       *
552       * <p> Precondition: IfCmp.conforms(cb)
553       *
554       * @param cb the conditional branch instruction
555       * @param target the target instruction (real instruction) of the conditional
556       *               branch
557       * @return boolean result
558       */
559      private boolean isFlipCandidate(Instruction cb, Instruction target) {
560        // condition 1: is next instruction a GOTO?
561        Instruction next = cb.nextInstructionInCodeOrder();
562        if (!Goto.conforms(next)) {
563          return false;
564        }
565        // condition 2: is the target of the conditional branch the
566        //  next instruction after the GOTO?
567        next = firstRealInstructionFollowing(next);
568        if (next != target) {
569          return false;
570        }
571        // got this far.  It's a candidate.
572        return true;
573      }
574    
575      /**
576       * Flip a conditional branch and remove the trailing goto.
577       * See comment 3) of processConditionalBranch
578       *
579       * <p> Precondition isFlipCandidate(cb)
580       * @param cb the conditional branch instruction
581       */
582      private void flipConditionalBranch(Instruction cb) {
583        // get the trailing GOTO instruction
584        Instruction g = cb.nextInstructionInCodeOrder();
585        BranchOperand gTarget = (BranchOperand) (Goto.getTarget(g).copy());
586        // now flip the test and set the new target
587        IfCmp.setCond(cb, IfCmp.getCond(cb).flipCode());
588        IfCmp.setTarget(cb, gTarget);
589    
590        // Update the branch probability.  It is now the opposite
591        cb.flipBranchProbability();
592        // finally, remove the trailing GOTO instruction
593        g.remove();
594      }
595    
596      /**
597       * Generate a boolean operation opcode
598       *
599       * <pre>
600       * 1) IF br != 0 THEN x=1 ELSE x=0       replaced by INT_MOVE x=br
601       *    IF br == 0 THEN x=0 ELSE x=1
602       * 2) IF br == 0 THEN x=1 ELSE x=0       replaced by BOOLEAN_NOT x=br
603       *    IF br != 0 THEN x=0 ELSE x=1
604       * 3) IF v1 ~ v2 THEN x=1 ELSE x=0       replaced by BOOLEAN_CMP x=v1,v2,~
605       * </pre>
606       *
607       *
608       * @param cb conditional branch instruction
609       * @param res the operand for result
610       * @param val1 value being compared
611       * @param val2 value being compared with
612       * @param cond comparison condition
613       */
614      private void booleanCompareHelper(Instruction cb, RegisterOperand res, Operand val1, Operand val2,
615                                        ConditionOperand cond) {
616        if ((val1 instanceof RegisterOperand) &&
617            ((RegisterOperand) val1).getType().isBooleanType() &&
618            (val2 instanceof IntConstantOperand)) {
619          int value = ((IntConstantOperand) val2).value;
620          if (VM.VerifyAssertions && (value != 0) && (value != 1)) {
621            throw new OptimizingCompilerException("Invalid boolean value");
622          }
623          int c = cond.evaluate(value, 0);
624          if (c == ConditionOperand.TRUE) {
625            Unary.mutate(cb, BOOLEAN_NOT, res, val1);
626            return;
627          } else if (c == ConditionOperand.FALSE) {
628            Move.mutate(cb, INT_MOVE, res, val1);
629            return;
630          }
631        }
632        BooleanCmp.mutate(cb,
633                          (cb.operator() == REF_IFCMP) ? BOOLEAN_CMP_ADDR : BOOLEAN_CMP_INT,
634                          res,
635                          val1,
636                          val2,
637                          cond,
638                          new BranchProfileOperand());
639      }
640    
641      /**
642       * Attempt to generate a straight-line sequence using conditional move
643       * instructions, to replace a diamond control flow structure.
644       *
645       * <p>Suppose we have the following code, where e{n} is an expression:
646       * <pre>
647       * if (a op b) {
648       *   x = e2;
649       *   y = e3;
650       * } else {
651       *   z = e4;
652       *   x = e5;
653       * }
654       * </pre>
655       * We would transform this to:
656       * <pre>
657       * t1 = a;
658       * t2 = b;
659       * t3 = e2;
660       * t4 = e3;
661       * t5 = e4;
662       * t6 = e5;
663       * COND MOVE [if (t1 op t2) x := t3 else x := t6 ];
664       * COND MOVE [if (t1 op t2) y := t4 else y := y];
665       * COND MOVE [if (t1 op t2) z := z  else z := t5];
666       * </pre>
667       *
668       * <p>Note that we rely on other optimizations (eg. copy propagation) to
669       * clean up some of this unnecessary mess.
670       *
671       * <p>Note that in this example, we've increased the shortest path by 2
672       * expression evaluations, 2 moves, and 3 cond moves, but eliminated one
673       * conditional branch.
674       *
675       * <p>We apply a cost heuristic to guide this transformation:
676       * We will eliminate a conditional branch iff it increases the shortest
677       * path by no more than 'k' operations.  Currently, we count each
678       * instruction (alu, move, or cond move) as 1 evaluation.
679       * The parameter k is specified by OPT\_Options.COND_MOVE_CUTOFF.
680       *
681       * <p> In the example above, since we've increased the shortest path by
682       * 6 instructions, we will only perform the transformation if k >= 7.
683       *
684       * <p> TODO items
685       * <ul>
686       * <li> consider smarter cost heuristics
687       * <li> enhance downstream code generation to avoid redundant evaluation
688       * of condition codes.
689       * </ul>
690       *
691       * @param ir governing IR
692       * @param bb basic block of cb
693       * @param cb conditional branch instruction
694       * @return true if the transformation succeeds, false otherwise
695       */
696      private boolean generateCondMove(IR ir, BasicBlock bb, Instruction cb) {
697        final boolean VERBOSE=false;
698        if (!VM.BuildForIA32) return false;
699        if (!IfCmp.conforms(cb)) return false;
700    
701        if (VERBOSE) System.out.println("CondMove: Looking to optimize "+cb);
702        // Don't generate CMOVs for branches that can be folded.
703        if (IfCmp.getVal1(cb).isConstant() && IfCmp.getVal2(cb).isConstant()) {
704          if (VERBOSE) System.out.println("CondMove: fail - could be folded");
705          return false;
706        }
707    
708        // see if bb is the root of an if-then-else.
709        Diamond diamond = Diamond.buildDiamond(bb);
710        if (diamond == null) {
711          if (VERBOSE) System.out.println("CondMove: fail - no diamond");
712          return false;
713        }
714        BasicBlock taken = diamond.getTaken();
715        BasicBlock notTaken = diamond.getNotTaken();
716    
717        // do not perform the transformation if either branch of the diamond
718        // has a taboo instruction (eg., a PEI, store or divide).
719        if (taken != null && hasCMTaboo(taken)) {
720          if (VERBOSE) System.out.println("CondMove: fail - taken branch has taboo instruction");
721          return false;
722        }
723        if (notTaken != null && hasCMTaboo(notTaken)) {
724          if (VERBOSE) System.out.println("CondMove: fail - not taken branch has taboo instruction");
725          return false;
726        }
727    
728        ConditionOperand cond = IfCmp.getCond(cb);
729    
730        // Do not generate when we don't know the branch probability or
731        // when branch probability is high. CMOVs reduce performance of
732        // the out-of-order engine (Intel Optimization Guide -
733        // Assembly/Compiler Coding Rule 2).
734        // Ignore in the case of an abs() method as we can create tighter
735        // instructions.
736        BranchProfileOperand profile = IfCmp.getBranchProfile(cb);
737        if ((Math.abs(profile.takenProbability - 0.5) >= ir.options.CONTROL_WELL_PREDICTED_CUTOFF) &&
738            !(cb.position != null && cb.position.method.getName() == ABS && cond.isFLOATINGPOINT())) {
739          if (VERBOSE)
740            System.out.println("CondMove: fail - branch could be well predicted by branch predictor: "+
741                profile.takenProbability);
742          return false;
743        }
744    
745        // if we must generate FCMP, make sure the condition code is OK
746        if (cond.isFLOATINGPOINT()) {
747          if (!fpConditionOK(cond)) {
748            // Condition not OK, but maybe if we flip the operands
749            if (!fpConditionOK(cond.flipOperands())) {
750              // still not ok so flip operands back
751              cond.flipOperands();
752              // give up or for SSE2 check if this is a floating point compare
753              // controlling just floating point moves
754              if (!VM.BuildForSSE2Full || hasFloatingPointDef(taken, true) || hasFloatingPointDef(notTaken, true)) {
755                if (VERBOSE) System.out.println("CondMove: fail - fp condition not OK: "+cond);
756                return false;
757              }
758            } else {
759              // flip operands
760              Operand val1 = IfCmp.getVal1(cb);
761              Operand val2 = IfCmp.getVal2(cb);
762              IfCmp.setVal1(cb, val2);
763              IfCmp.setVal2(cb, val1);
764            }
765          }
766        }
767    
768        if (!cond.isFLOATINGPOINT()) {
769          // Can only generate moves of floating point values for floating point
770          // compares or for unsigned compares in x87
771          if (VM.BuildForSSE2Full || !cond.isUNSIGNED()) {
772            if (hasFloatingPointDef(taken, false) || hasFloatingPointDef(notTaken, false)) {
773              if (VERBOSE)
774                System.out.println("CondMove: fail - not allowed integer condition controlling floating conditional move");
775              return false;
776            }
777          }
778        }
779    
780        // For now, do not generate CMOVs for longs.
781        if (hasLongDef(taken) || hasLongDef(notTaken)) {
782          return false;
783        }
784    
785        // count the number of expression evaluations in each side of the
786        // diamond
787        int takenCost = 0;
788        int notTakenCost = 0;
789        if (taken != null) takenCost = evaluateCost(taken);
790        if (notTaken != null) notTakenCost = evaluateCost(notTaken);
791    
792        // evaluate whether it's profitable.
793        int shortestCost = Math.min(takenCost, notTakenCost);
794        int xformCost = 2 * (takenCost + notTakenCost);
795        int k = ir.options.CONTROL_COND_MOVE_CUTOFF;
796        if (xformCost - shortestCost > k) {
797          if (VERBOSE) System.out.println("CondMove: fail - cost too high");
798          return false;
799        }
800    
801        // Perform the transformation!
802        doCondMove(ir, diamond, cb);
803        return true;
804      }
805    
806      /**
807       * Is a specified condition operand 'safe' to transfer into an FCMP
808       * instruction?
809       */
810      private boolean fpConditionOK(ConditionOperand c) {
811        // FCOMI sets ZF, PF, and CF as follows:
812        // Compare Results      ZF     PF      CF
813        // left > right          0      0       0
814        // left < right          0      0       1
815        // left == right         1      0       0
816        // UNORDERED             1      1       1
817        switch (c.value) {
818        case ConditionOperand.CMPL_EQUAL:
819          return false; // (ZF == 1) but ordered
820        case ConditionOperand.CMPL_NOT_EQUAL:
821          return false; // (ZF == 0) but unordered
822        case ConditionOperand.CMPG_LESS:
823          return false; // (CF == 1) but ordered
824        case ConditionOperand.CMPG_GREATER_EQUAL:
825          return false; // (CF == 0) but unordered
826        case ConditionOperand.CMPG_LESS_EQUAL:
827          return false; // (CF == 1 || ZF == 1) but ordered
828        case ConditionOperand.CMPG_GREATER:
829          return false; // (CF == 0 && ZF == 0) but unordered
830    
831        case ConditionOperand.CMPL_GREATER:
832          return true; // (CF == 0 && ZF == 0) and ordered
833        case ConditionOperand.CMPL_LESS_EQUAL:
834          return true; // (CF == 1 || ZF == 1) and unordered
835        case ConditionOperand.CMPL_GREATER_EQUAL:
836          return true; // (CF == 0) and ordered
837        case ConditionOperand.CMPL_LESS:
838          return true; // (CF == 1) and unordered
839        default:
840          OptimizingCompilerException.UNREACHABLE();
841        return false; // keep jikes happy
842        }
843      }
844    
845      /**
846       * Do any of the instructions in a basic block define a floating-point
847       * register?
848       *
849       * @param bb basic block to search
850       * @param invert invert the sense of the search
851       */
852      private static boolean hasFloatingPointDef(BasicBlock bb, boolean invert) {
853        if (bb == null) return false;
854        for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements();) {
855          Instruction s = e.nextElement();
856          for (Enumeration<Operand> d = s.getDefs(); d.hasMoreElements();) {
857            Operand def = d.nextElement();
858            if (def.isRegister()) {
859              if (def.asRegister().getRegister().isFloatingPoint() != invert) return true;
860            }
861          }
862        }
863        return false;
864      }
865    
866      /**
867       * Do any of the instructions in a basic block define a long
868       * register?
869       */
870      private boolean hasLongDef(BasicBlock bb) {
871        if (bb == null) return false;
872        for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements();) {
873          Instruction s = e.nextElement();
874          for (Enumeration<Operand> d = s.getDefs(); d.hasMoreElements();) {
875            Operand def = d.nextElement();
876            if (def.isRegister()) {
877              if (def.asRegister().getRegister().isLong()) return true;
878            }
879          }
880        }
881        return false;
882      }
883    
884      /**
885       * Do any of the instructions in a basic block preclude eliminating the
886       * basic block with conditional moves?
887       */
888      private boolean hasCMTaboo(BasicBlock bb) {
889    
890        if (bb == null) return false;
891    
892        // Note: it is taboo to assign more than once to any register in the
893        // block.
894        HashSet<Register> defined = new HashSet<Register>();
895    
896        for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements();) {
897          Instruction s = e.nextElement();
898          if (s.isBranch()) continue;
899          // for now, only the following opcodes are legal.
900          switch (s.operator.opcode) {
901            case INT_MOVE_opcode:
902            case REF_MOVE_opcode:
903            case DOUBLE_MOVE_opcode:
904            case FLOAT_MOVE_opcode:
905            case INT_ADD_opcode:
906            case REF_ADD_opcode:
907            case FLOAT_ADD_opcode:
908            case DOUBLE_ADD_opcode:
909            case INT_SUB_opcode:
910            case REF_SUB_opcode:
911            case FLOAT_SUB_opcode:
912            case DOUBLE_SUB_opcode:
913            case INT_MUL_opcode:
914            case FLOAT_MUL_opcode:
915            case DOUBLE_MUL_opcode:
916            case INT_NEG_opcode:
917            case FLOAT_NEG_opcode:
918            case DOUBLE_NEG_opcode:
919            case REF_SHL_opcode:
920            case INT_SHL_opcode:
921            case REF_SHR_opcode:
922            case INT_SHR_opcode:
923            case REF_USHR_opcode:
924            case INT_USHR_opcode:
925            case REF_AND_opcode:
926            case INT_AND_opcode:
927            case REF_OR_opcode:
928            case INT_OR_opcode:
929            case REF_XOR_opcode:
930            case INT_XOR_opcode:
931            case REF_NOT_opcode:
932            case INT_NOT_opcode:
933            case INT_2BYTE_opcode:
934            case INT_2USHORT_opcode:
935            case INT_2SHORT_opcode:
936            case FLOAT_2DOUBLE_opcode:
937            case DOUBLE_2FLOAT_opcode:
938              // these are OK.
939              break;
940            default:
941              return true;
942          }
943    
944          // make sure no register is defined more than once in this block.
945          for (Enumeration<Operand> defs = s.getDefs(); defs.hasMoreElements();) {
946            Operand def = defs.nextElement();
947            if (VM.VerifyAssertions) VM._assert(def.isRegister());
948            Register r = def.asRegister().getRegister();
949            if (defined.contains(r)) return true;
950            defined.add(r);
951          }
952        }
953    
954        return false;
955      }
956    
957      /**
958       * Evaluate the cost of a basic block, in number of real instructions.
959       */
960      private int evaluateCost(BasicBlock bb) {
961        int result = 0;
962        for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements();) {
963          Instruction s = e.nextElement();
964          if (!s.isBranch()) result++;
965        }
966        return result;
967      }
968    
969      /**
970       * For each real non-branch instruction s in bb,
971       * <ul>
972       * <li> Copy s to s', and store s' in the returned array
973       * <li> Insert the function s->s' in the map
974       * </ul>
975       */
976      private Instruction[] copyAndMapInstructions(BasicBlock bb, HashMap<Instruction, Instruction> map) {
977        if (bb == null) return new Instruction[0];
978    
979        int count = 0;
980        // first count the number of instructions
981        for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements();) {
982          Instruction s = e.nextElement();
983          if (s.isBranch()) continue;
984          count++;
985        }
986        // now copy.
987        Instruction[] result = new Instruction[count];
988        int i = 0;
989        for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements();) {
990          Instruction s = e.nextElement();
991          if (s.isBranch()) continue;
992          Instruction sprime = s.copyWithoutLinks();
993          result[i++] = sprime;
994          map.put(s, sprime);
995        }
996        return result;
997      }
998    
999      /**
1000       * For each in a set of instructions, rewrite every def to use a new
1001       * temporary register.  If a rewritten def is subsequently used, then
1002       * use the new temporary register instead.
1003       */
1004      private void rewriteWithTemporaries(Instruction[] set, IR ir) {
1005    
1006        // Maintain a mapping holding the new name for each register
1007        HashMap<Register, Register> map = new HashMap<Register, Register>();
1008        for (Instruction s : set) {
1009          // rewrite the uses to use the new names
1010          for (Enumeration<Operand> e = s.getUses(); e.hasMoreElements();) {
1011            Operand use = e.nextElement();
1012            if (use != null && use.isRegister()) {
1013              Register r = use.asRegister().getRegister();
1014              Register temp = map.get(r);
1015              if (temp != null) {
1016                use.asRegister().setRegister(temp);
1017              }
1018            }
1019          }
1020    
1021          if (VM.VerifyAssertions) VM._assert(s.getNumberOfDefs() == 1);
1022    
1023          Operand def = s.getDefs().nextElement();
1024          RegisterOperand rDef = def.asRegister();
1025          RegisterOperand temp = ir.regpool.makeTemp(rDef);
1026          map.put(rDef.getRegister(), temp.getRegister());
1027          s.replaceOperand(def, temp);
1028        }
1029      }
1030    
1031      /**
1032       * Insert each instruction in a list before instruction s
1033       */
1034      private void insertBefore(Instruction[] list, Instruction s) {
1035        for (Instruction x : list) {
1036          s.insertBefore(x);
1037        }
1038      }
1039    
1040      /**
1041       * Perform the transformation to replace conditional branch with a
1042       * sequence using conditional moves.
1043       *
1044       * @param ir governing IR
1045       * @param diamond the IR diamond structure to replace
1046       * @param cb conditional branch instruction at the head of the diamond
1047       */
1048      private void doCondMove(IR ir, Diamond diamond, Instruction cb) {
1049        BasicBlock taken = diamond.getTaken();
1050        BasicBlock notTaken = diamond.getNotTaken();
1051    
1052        // for each non-branch instruction s in the diamond,
1053        // copy s to a new instruction s'
1054        // and store a mapping from s to s'
1055        HashMap<Instruction, Instruction> takenInstructions = new HashMap<Instruction, Instruction>();
1056        Instruction[] takenInstructionList = copyAndMapInstructions(taken, takenInstructions);
1057    
1058        HashMap<Instruction, Instruction> notTakenInstructions = new HashMap<Instruction, Instruction>();
1059        Instruction[] notTakenInstructionList = copyAndMapInstructions(notTaken, notTakenInstructions);
1060    
1061        // Extract the values and condition from the conditional branch.
1062        Operand val1 = IfCmp.getVal1(cb);
1063        Operand val2 = IfCmp.getVal2(cb);
1064        ConditionOperand cond = IfCmp.getCond(cb);
1065    
1066        // Copy val1 and val2 to temporaries, just in case they're defined in
1067        // the diamond.  If they're not defined in the diamond, copy prop
1068        // should clean these moves up.
1069        RegisterOperand tempVal1 = ir.regpool.makeTemp(val1);
1070        Operator op = IRTools.getMoveOp(tempVal1.getType());
1071        cb.insertBefore(Move.create(op, tempVal1.copyRO(), val1.copy()));
1072        RegisterOperand tempVal2 = ir.regpool.makeTemp(val2);
1073        op = IRTools.getMoveOp(tempVal2.getType());
1074        cb.insertBefore(Move.create(op, tempVal2.copyRO(), val2.copy()));
1075    
1076        // For each instruction in each temporary set, rewrite it to def a new
1077        // temporary, and insert it before the branch.
1078        rewriteWithTemporaries(takenInstructionList, ir);
1079        rewriteWithTemporaries(notTakenInstructionList, ir);
1080        insertBefore(takenInstructionList, cb);
1081        insertBefore(notTakenInstructionList, cb);
1082    
1083        // For each register defined in the TAKEN branch, save a mapping to
1084        // the corresponding conditional move.
1085        HashMap<Register, Instruction> takenMap = new HashMap<Register, Instruction>();
1086    
1087        // Now insert conditional moves to replace each instruction in the diamond.
1088        // First handle the taken branch.
1089        if (taken != null) {
1090          for (Enumeration<Instruction> e = taken.forwardRealInstrEnumerator(); e.hasMoreElements();) {
1091            Instruction s = e.nextElement();
1092            if (s.isBranch()) continue;
1093            Operand def = s.getDefs().nextElement();
1094            // if the register does not span a basic block, it is a temporary
1095            // that will now be dead
1096            if (def.asRegister().getRegister().spansBasicBlock()) {
1097              Instruction tempS = takenInstructions.get(s);
1098              RegisterOperand temp = (RegisterOperand) tempS.getDefs().nextElement();
1099              op = IRTools.getCondMoveOp(def.asRegister().getType());
1100              Instruction cmov =
1101                  CondMove.create(op,
1102                                  def.asRegister(),
1103                                  tempVal1.copy(),
1104                                  tempVal2.copy(),
1105                                  cond.copy().asCondition(),
1106                                  temp.copy(),
1107                                  def.copy());
1108              takenMap.put(def.asRegister().getRegister(), cmov);
1109              cb.insertBefore(cmov);
1110            }
1111            s.remove();
1112          }
1113        }
1114        // For each register defined in the NOT-TAKEN branch, save a mapping to
1115        // the corresponding conditional move.
1116        HashMap<Register, Instruction> notTakenMap = new HashMap<Register, Instruction>();
1117        // Next handle the not taken branch.
1118        if (notTaken != null) {
1119          for (Enumeration<Instruction> e = notTaken.forwardRealInstrEnumerator(); e.hasMoreElements();) {
1120            Instruction s = e.nextElement();
1121            if (s.isBranch()) continue;
1122            Operand def = s.getDefs().nextElement();
1123            // if the register does not span a basic block, it is a temporary
1124            // that will now be dead
1125            if (def.asRegister().getRegister().spansBasicBlock()) {
1126              Instruction tempS = notTakenInstructions.get(s);
1127              RegisterOperand temp = (RegisterOperand) tempS.getDefs().nextElement();
1128    
1129              Instruction prevCmov = takenMap.get(def.asRegister().getRegister());
1130              if (prevCmov != null) {
1131                // if this register was also defined in the taken branch, change
1132                // the previous cmov with a different 'False' Value
1133                CondMove.setFalseValue(prevCmov, temp.copy());
1134                notTakenMap.put(def.asRegister().getRegister(), prevCmov);
1135              } else {
1136                // create a new cmov instruction
1137                op = IRTools.getCondMoveOp(def.asRegister().getType());
1138                Instruction cmov =
1139                    CondMove.create(op,
1140                                    def.asRegister(),
1141                                    tempVal1.copy(),
1142                                    tempVal2.copy(),
1143                                    cond.copy().asCondition(),
1144                                    def.copy(),
1145                                    temp.copy());
1146                cb.insertBefore(cmov);
1147                notTakenMap.put(def.asRegister().getRegister(), cmov);
1148              }
1149            }
1150            s.remove();
1151          }
1152        }
1153    
1154        // Mutate the conditional branch into a GOTO.
1155        BranchOperand target = diamond.getBottom().makeJumpTarget();
1156        Goto.mutate(cb, GOTO, target);
1157    
1158        // Delete a potential GOTO after cb.
1159        Instruction next = cb.nextInstructionInCodeOrder();
1160        if (next.operator != BBEND) {
1161          next.remove();
1162        }
1163    
1164        // Recompute the CFG.
1165        diamond.getTop().recomputeNormalOut(ir); // fix the CFG
1166      }
1167    
1168      /**
1169       * Attempt to generate a boolean compare opcode from a conditional branch.
1170       *
1171       * <pre>
1172       * 1)   IF .. GOTO A          replaced by  BOOLEAN_CMP x=..
1173       *      x = 0
1174       *      GOTO B
1175       *   A: x = 1
1176       *   B: ...
1177       * </pre>
1178       *
1179       * <p> Precondition: <code>IfCmp.conforms(<i>cb</i>)</code>
1180       *
1181       *
1182       * @param ir governing IR
1183       * @param bb basic block of cb
1184       * @param cb conditional branch instruction
1185       * @return true if the transformation succeeds, false otherwise
1186       */
1187      private boolean generateBooleanCompare(IR ir, BasicBlock bb, Instruction cb, BasicBlock tb) {
1188    
1189        if ((cb.operator() != INT_IFCMP) && (cb.operator() != REF_IFCMP)) {
1190          return false;
1191        }
1192        // make sure this is the last branch in the block
1193        if (cb.nextInstructionInCodeOrder().operator() != BBEND) {
1194          return false;
1195        }
1196        Operand val1 = IfCmp.getVal1(cb);
1197        Operand val2 = IfCmp.getVal2(cb);
1198        ConditionOperand condition = IfCmp.getCond(cb);
1199        // "not taken" path
1200        BasicBlock fb = cb.getBasicBlock().getNotTakenNextBlock();
1201        // make sure it's a diamond
1202        if (tb.getNumberOfNormalOut() != 1) {
1203          return false;
1204        }
1205        if (fb.getNumberOfNormalOut() != 1) {
1206          return false;
1207        }
1208        BasicBlock jb = fb.getNormalOut().nextElement();               // join block
1209        // make sure it's a diamond
1210        if (!tb.pointsOut(jb)) {
1211          return false;
1212        }
1213        Instruction ti = tb.firstRealInstruction();
1214        Instruction fi = fb.firstRealInstruction();
1215        // make sure the instructions in target blocks are either both moves
1216        // or both returns
1217        if (ti == null || fi == null) {
1218          return false;
1219        }
1220        if (ti.operator() != fi.operator()) {
1221          return false;
1222        }
1223        if (ti.operator != RETURN && ti.operator() != INT_MOVE) {
1224          return false;
1225        }
1226        //
1227        // WARNING: This code is currently NOT exercised!
1228        //
1229        if (ti.operator() == RETURN) {
1230          // make sure each of the target blocks contains only one instruction
1231          if (ti != tb.lastRealInstruction()) {
1232            return false;
1233          }
1234          if (fi != fb.lastRealInstruction()) {
1235            return false;
1236          }
1237          Operand tr = Return.getVal(ti);
1238          Operand fr = Return.getVal(fi);
1239          // make sure we're returning constants
1240          if (!(tr instanceof IntConstantOperand) || !(fr instanceof IntConstantOperand)) {
1241            return false;
1242          }
1243          int tv = ((IntConstantOperand) tr).value;
1244          int fv = ((IntConstantOperand) fr).value;
1245          if (!((tv == 1 && fv == 0) || (tv == 1 && fv == 0))) {
1246            return false;
1247          }
1248          RegisterOperand t = ir.regpool.makeTemp(TypeReference.Boolean);
1249          // Cases 1) and 2)
1250          if (tv == 0) {
1251            condition = condition.flipCode();
1252          }
1253          booleanCompareHelper(cb, t, val1.copy(), val2.copy(), condition);
1254          cb.insertAfter(Return.create(RETURN, t.copyD2U()));
1255        } else {      // (ti.operator() == INT_MOVE)
1256          // make sure each of the target blocks only does the move
1257          if (ti != tb.lastRealInstruction() && ti.nextInstructionInCodeOrder().operator() != GOTO) {
1258            return false;
1259          }
1260          if (fi != fb.lastRealInstruction() && fi.nextInstructionInCodeOrder().operator() != GOTO) {
1261            return false;
1262          }
1263          RegisterOperand t = Move.getResult(ti);
1264          // make sure both moves are to the same register
1265          if (t.getRegister() != Move.getResult(fi).getRegister()) {
1266            return false;
1267          }
1268          Operand tr = Move.getVal(ti);
1269          Operand fr = Move.getVal(fi);
1270          // make sure we're assigning constants
1271          if (!(tr instanceof IntConstantOperand) || !(fr instanceof IntConstantOperand)) {
1272            return false;
1273          }
1274          int tv = ((IntConstantOperand) tr).value;
1275          int fv = ((IntConstantOperand) fr).value;
1276          if (!((tv == 1 && fv == 0) || (tv == 0 && fv == 1))) {
1277            return false;
1278          }
1279          // Cases 3) and 4)
1280          if (tv == 0) {
1281            condition = condition.flipCode();
1282          }
1283          booleanCompareHelper(cb, t.copyRO(), val1.copy(), val2.copy(), condition);
1284          Instruction next = cb.nextInstructionInCodeOrder();
1285          if (next.operator() == GOTO) {
1286            Goto.setTarget(next, jb.makeJumpTarget());
1287          } else {
1288            cb.insertAfter(jb.makeGOTO());
1289          }
1290        }
1291        // fixup CFG
1292        bb.deleteOut(tb);
1293        bb.deleteOut(fb);
1294        bb.insertOut(jb);           // Note: if we processed returns,
1295        // jb is the exit node.
1296        return true;
1297      }
1298    }