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 */
013package org.jikesrvm.compilers.opt.controlflow;
014
015import static org.jikesrvm.compilers.opt.ir.IRTools.CPOS;
016import static org.jikesrvm.compilers.opt.ir.Operators.BBEND;
017import static org.jikesrvm.compilers.opt.ir.Operators.BOOLEAN_CMP_ADDR;
018import static org.jikesrvm.compilers.opt.ir.Operators.BOOLEAN_CMP_INT;
019import static org.jikesrvm.compilers.opt.ir.Operators.BOOLEAN_NOT;
020import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_2FLOAT_opcode;
021import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ADD_opcode;
022import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_MOVE_opcode;
023import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_MUL_opcode;
024import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_NEG_opcode;
025import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_SUB_opcode;
026import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_2DOUBLE_opcode;
027import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_ADD_opcode;
028import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_MOVE_opcode;
029import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_MUL_opcode;
030import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_NEG_opcode;
031import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_SUB_opcode;
032import static org.jikesrvm.compilers.opt.ir.Operators.GOTO;
033import static org.jikesrvm.compilers.opt.ir.Operators.INT_2BYTE_opcode;
034import static org.jikesrvm.compilers.opt.ir.Operators.INT_2SHORT_opcode;
035import static org.jikesrvm.compilers.opt.ir.Operators.INT_2USHORT_opcode;
036import static org.jikesrvm.compilers.opt.ir.Operators.INT_ADD_opcode;
037import static org.jikesrvm.compilers.opt.ir.Operators.INT_AND_opcode;
038import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP;
039import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP2;
040import static org.jikesrvm.compilers.opt.ir.Operators.INT_MOVE;
041import static org.jikesrvm.compilers.opt.ir.Operators.INT_MOVE_opcode;
042import static org.jikesrvm.compilers.opt.ir.Operators.INT_MUL_opcode;
043import static org.jikesrvm.compilers.opt.ir.Operators.INT_NEG_opcode;
044import static org.jikesrvm.compilers.opt.ir.Operators.INT_NOT_opcode;
045import static org.jikesrvm.compilers.opt.ir.Operators.INT_OR_opcode;
046import static org.jikesrvm.compilers.opt.ir.Operators.INT_SHL_opcode;
047import static org.jikesrvm.compilers.opt.ir.Operators.INT_SHR_opcode;
048import static org.jikesrvm.compilers.opt.ir.Operators.INT_SUB_opcode;
049import static org.jikesrvm.compilers.opt.ir.Operators.INT_USHR_opcode;
050import static org.jikesrvm.compilers.opt.ir.Operators.INT_XOR_opcode;
051import static org.jikesrvm.compilers.opt.ir.Operators.REF_ADD_opcode;
052import static org.jikesrvm.compilers.opt.ir.Operators.REF_AND_opcode;
053import static org.jikesrvm.compilers.opt.ir.Operators.REF_IFCMP;
054import static org.jikesrvm.compilers.opt.ir.Operators.REF_MOVE_opcode;
055import static org.jikesrvm.compilers.opt.ir.Operators.REF_NOT_opcode;
056import static org.jikesrvm.compilers.opt.ir.Operators.REF_OR_opcode;
057import static org.jikesrvm.compilers.opt.ir.Operators.REF_SHL_opcode;
058import static org.jikesrvm.compilers.opt.ir.Operators.REF_SHR_opcode;
059import static org.jikesrvm.compilers.opt.ir.Operators.REF_SUB_opcode;
060import static org.jikesrvm.compilers.opt.ir.Operators.REF_USHR_opcode;
061import static org.jikesrvm.compilers.opt.ir.Operators.REF_XOR_opcode;
062import static org.jikesrvm.compilers.opt.ir.Operators.RETURN;
063
064import java.util.Enumeration;
065import java.util.HashMap;
066import java.util.HashSet;
067
068import org.jikesrvm.VM;
069import org.jikesrvm.classloader.Atom;
070import org.jikesrvm.classloader.TypeReference;
071import org.jikesrvm.compilers.opt.OptimizingCompilerException;
072import org.jikesrvm.compilers.opt.ir.BasicBlock;
073import org.jikesrvm.compilers.opt.ir.BooleanCmp;
074import org.jikesrvm.compilers.opt.ir.CondMove;
075import org.jikesrvm.compilers.opt.ir.Goto;
076import org.jikesrvm.compilers.opt.ir.IR;
077import org.jikesrvm.compilers.opt.ir.IRTools;
078import org.jikesrvm.compilers.opt.ir.IfCmp;
079import org.jikesrvm.compilers.opt.ir.IfCmp2;
080import org.jikesrvm.compilers.opt.ir.InlineGuard;
081import org.jikesrvm.compilers.opt.ir.Instruction;
082import org.jikesrvm.compilers.opt.ir.Move;
083import org.jikesrvm.compilers.opt.ir.Operator;
084import org.jikesrvm.compilers.opt.ir.Register;
085import org.jikesrvm.compilers.opt.ir.Return;
086import org.jikesrvm.compilers.opt.ir.Unary;
087import org.jikesrvm.compilers.opt.ir.operand.BranchOperand;
088import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand;
089import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand;
090import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
091import org.jikesrvm.compilers.opt.ir.operand.Operand;
092import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
093
094/**
095 * Perform simple peephole optimizations for branches.
096 */
097public 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 {@code 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   * @param c operand to check
811   * @return whether the operand is 'safe'
812   */
813  private boolean fpConditionOK(ConditionOperand c) {
814    // FCOMI sets ZF, PF, and CF as follows:
815    // Compare Results      ZF     PF      CF
816    // left > right          0      0       0
817    // left < right          0      0       1
818    // left == right         1      0       0
819    // UNORDERED             1      1       1
820    switch (c.value) {
821    case ConditionOperand.CMPL_EQUAL:
822      return false; // (ZF == 1) but ordered
823    case ConditionOperand.CMPL_NOT_EQUAL:
824      return false; // (ZF == 0) but unordered
825    case ConditionOperand.CMPG_LESS:
826      return false; // (CF == 1) but ordered
827    case ConditionOperand.CMPG_GREATER_EQUAL:
828      return false; // (CF == 0) but unordered
829    case ConditionOperand.CMPG_LESS_EQUAL:
830      return false; // (CF == 1 || ZF == 1) but ordered
831    case ConditionOperand.CMPG_GREATER:
832      return false; // (CF == 0 && ZF == 0) but unordered
833
834    case ConditionOperand.CMPL_GREATER:
835      return true; // (CF == 0 && ZF == 0) and ordered
836    case ConditionOperand.CMPL_LESS_EQUAL:
837      return true; // (CF == 1 || ZF == 1) and unordered
838    case ConditionOperand.CMPL_GREATER_EQUAL:
839      return true; // (CF == 0) and ordered
840    case ConditionOperand.CMPL_LESS:
841      return true; // (CF == 1) and unordered
842    default:
843      OptimizingCompilerException.UNREACHABLE();
844    return false;
845    }
846  }
847
848  /**
849   * Do any of the instructions in a basic block define a floating-point
850   * register?
851   *
852   * @param bb basic block to search
853   * @param invert {@code true} if and only if the sense of the search
854   *  should be inverted
855   * @return whether a floating point register (or a non-floating point register)
856   *  is defined in the block
857   */
858  private static boolean hasFloatingPointDef(BasicBlock bb, boolean invert) {
859    if (bb == null) return false;
860    for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements();) {
861      Instruction s = e.nextElement();
862      for (Enumeration<Operand> d = s.getDefs(); d.hasMoreElements();) {
863        Operand def = d.nextElement();
864        if (def.isRegister()) {
865          if (def.asRegister().getRegister().isFloatingPoint() != invert) return true;
866        }
867      }
868    }
869    return false;
870  }
871
872  /**
873   * Do any of the instructions in a basic block define a long
874   * register?
875   *
876   * @param bb basic block to search
877   * @return whether an instruction in the block defines a long
878   *  register
879   */
880  private boolean hasLongDef(BasicBlock bb) {
881    if (bb == null) return false;
882    for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements();) {
883      Instruction s = e.nextElement();
884      for (Enumeration<Operand> d = s.getDefs(); d.hasMoreElements();) {
885        Operand def = d.nextElement();
886        if (def.isRegister()) {
887          if (def.asRegister().getRegister().isLong()) return true;
888        }
889      }
890    }
891    return false;
892  }
893
894  /**
895   * Do any of the instructions in a basic block preclude eliminating the
896   * basic block with conditional moves?
897   *
898   * @param bb the block to check
899   * @return whether the block must be retained
900   */
901  private boolean hasCMTaboo(BasicBlock bb) {
902
903    if (bb == null) return false;
904
905    // Note: it is taboo to assign more than once to any register in the
906    // block.
907    HashSet<Register> defined = new HashSet<Register>();
908
909    for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements();) {
910      Instruction s = e.nextElement();
911      if (s.isBranch()) continue;
912      // for now, only the following opcodes are legal.
913      switch (s.getOpcode()) {
914        case INT_MOVE_opcode:
915        case REF_MOVE_opcode:
916        case DOUBLE_MOVE_opcode:
917        case FLOAT_MOVE_opcode:
918        case INT_ADD_opcode:
919        case REF_ADD_opcode:
920        case FLOAT_ADD_opcode:
921        case DOUBLE_ADD_opcode:
922        case INT_SUB_opcode:
923        case REF_SUB_opcode:
924        case FLOAT_SUB_opcode:
925        case DOUBLE_SUB_opcode:
926        case INT_MUL_opcode:
927        case FLOAT_MUL_opcode:
928        case DOUBLE_MUL_opcode:
929        case INT_NEG_opcode:
930        case FLOAT_NEG_opcode:
931        case DOUBLE_NEG_opcode:
932        case REF_SHL_opcode:
933        case INT_SHL_opcode:
934        case REF_SHR_opcode:
935        case INT_SHR_opcode:
936        case REF_USHR_opcode:
937        case INT_USHR_opcode:
938        case REF_AND_opcode:
939        case INT_AND_opcode:
940        case REF_OR_opcode:
941        case INT_OR_opcode:
942        case REF_XOR_opcode:
943        case INT_XOR_opcode:
944        case REF_NOT_opcode:
945        case INT_NOT_opcode:
946        case INT_2BYTE_opcode:
947        case INT_2USHORT_opcode:
948        case INT_2SHORT_opcode:
949        case FLOAT_2DOUBLE_opcode:
950        case DOUBLE_2FLOAT_opcode:
951          // these are OK.
952          break;
953        default:
954          return true;
955      }
956
957      // make sure no register is defined more than once in this block.
958      for (Enumeration<Operand> defs = s.getDefs(); defs.hasMoreElements();) {
959        Operand def = defs.nextElement();
960        if (VM.VerifyAssertions) VM._assert(def.isRegister());
961        Register r = def.asRegister().getRegister();
962        if (defined.contains(r)) return true;
963        defined.add(r);
964      }
965    }
966
967    return false;
968  }
969
970  /**
971   * Evaluates the cost of a basic block, in number of real instructions
972   * excluding branches.
973   *
974   * @param bb the block to evaluate
975   * @return the number of real instruction, excluding branches.
976   */
977  private int evaluateCost(BasicBlock bb) {
978    int result = 0;
979    for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements();) {
980      Instruction s = e.nextElement();
981      if (!s.isBranch()) result++;
982    }
983    return result;
984  }
985
986  /**
987   * For each real non-branch instruction s in bb,
988   * <ul>
989   * <li> Copy s to s', and store s' in the returned array
990   * <li> Insert the function s-&gt;s' in the map
991   * </ul>
992   *
993   * @param bb the basic block to process
994   * @param map map for instructions (must be empty at the start)
995   * @return the copied instructions (which are not linked into an
996   *  instruction list)
997   */
998  private Instruction[] copyAndMapInstructions(BasicBlock bb, HashMap<Instruction, Instruction> map) {
999    if (bb == null) return new Instruction[0];
1000
1001    int count = 0;
1002    // first count the number of instructions
1003    for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements();) {
1004      Instruction s = e.nextElement();
1005      if (s.isBranch()) continue;
1006      count++;
1007    }
1008    // now copy.
1009    Instruction[] result = new Instruction[count];
1010    int i = 0;
1011    for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements();) {
1012      Instruction s = e.nextElement();
1013      if (s.isBranch()) continue;
1014      Instruction sprime = s.copyWithoutLinks();
1015      result[i++] = sprime;
1016      map.put(s, sprime);
1017    }
1018    return result;
1019  }
1020
1021  /**
1022   * For each in a set of instructions, rewrite every def to use a new
1023   * temporary register.  If a rewritten def is subsequently used, then
1024   * use the new temporary register instead.
1025   *
1026   * @param set the instructions to rewrite
1027   * @param ir the IR that will provide the temporary registers
1028   */
1029  private void rewriteWithTemporaries(Instruction[] set, IR ir) {
1030
1031    // Maintain a mapping holding the new name for each register
1032    HashMap<Register, Register> map = new HashMap<Register, Register>();
1033    for (Instruction s : set) {
1034      // rewrite the uses to use the new names
1035      for (Enumeration<Operand> e = s.getUses(); e.hasMoreElements();) {
1036        Operand use = e.nextElement();
1037        if (use != null && use.isRegister()) {
1038          Register r = use.asRegister().getRegister();
1039          Register temp = map.get(r);
1040          if (temp != null) {
1041            use.asRegister().setRegister(temp);
1042          }
1043        }
1044      }
1045
1046      if (VM.VerifyAssertions) VM._assert(s.getNumberOfDefs() == 1);
1047
1048      Operand def = s.getDefs().nextElement();
1049      RegisterOperand rDef = def.asRegister();
1050      RegisterOperand temp = ir.regpool.makeTemp(rDef);
1051      map.put(rDef.getRegister(), temp.getRegister());
1052      s.replaceOperand(def, temp);
1053    }
1054  }
1055
1056  /**
1057   * Inserts each instruction in a list before another instruction.
1058   *
1059   * @param list the instructions to insert before the other instruction
1060   * @param s the instruction before which the insertion should be done
1061   */
1062  private void insertBefore(Instruction[] list, Instruction s) {
1063    for (Instruction x : list) {
1064      s.insertBefore(x);
1065    }
1066  }
1067
1068  /**
1069   * Perform the transformation to replace conditional branch with a
1070   * sequence using conditional moves.
1071   *
1072   * @param ir governing IR
1073   * @param diamond the IR diamond structure to replace
1074   * @param cb conditional branch instruction at the head of the diamond
1075   */
1076  private void doCondMove(IR ir, Diamond diamond, Instruction cb) {
1077    BasicBlock taken = diamond.getTaken();
1078    BasicBlock notTaken = diamond.getNotTaken();
1079
1080    // for each non-branch instruction s in the diamond,
1081    // copy s to a new instruction s'
1082    // and store a mapping from s to s'
1083    HashMap<Instruction, Instruction> takenInstructions = new HashMap<Instruction, Instruction>();
1084    Instruction[] takenInstructionList = copyAndMapInstructions(taken, takenInstructions);
1085
1086    HashMap<Instruction, Instruction> notTakenInstructions = new HashMap<Instruction, Instruction>();
1087    Instruction[] notTakenInstructionList = copyAndMapInstructions(notTaken, notTakenInstructions);
1088
1089    // Extract the values and condition from the conditional branch.
1090    Operand val1 = IfCmp.getVal1(cb);
1091    Operand val2 = IfCmp.getVal2(cb);
1092    ConditionOperand cond = IfCmp.getCond(cb);
1093
1094    // Copy val1 and val2 to temporaries, just in case they're defined in
1095    // the diamond.  If they're not defined in the diamond, copy prop
1096    // should clean these moves up.
1097    RegisterOperand tempVal1 = ir.regpool.makeTemp(val1);
1098    Operator op = IRTools.getMoveOp(tempVal1.getType());
1099    cb.insertBefore(Move.create(op, tempVal1.copyRO(), val1.copy()));
1100    RegisterOperand tempVal2 = ir.regpool.makeTemp(val2);
1101    op = IRTools.getMoveOp(tempVal2.getType());
1102    cb.insertBefore(Move.create(op, tempVal2.copyRO(), val2.copy()));
1103
1104    // For each instruction in each temporary set, rewrite it to def a new
1105    // temporary, and insert it before the branch.
1106    rewriteWithTemporaries(takenInstructionList, ir);
1107    rewriteWithTemporaries(notTakenInstructionList, ir);
1108    insertBefore(takenInstructionList, cb);
1109    insertBefore(notTakenInstructionList, cb);
1110
1111    // For each register defined in the TAKEN branch, save a mapping to
1112    // the corresponding conditional move.
1113    HashMap<Register, Instruction> takenMap = new HashMap<Register, Instruction>();
1114
1115    // Now insert conditional moves to replace each instruction in the diamond.
1116    // First handle the taken branch.
1117    if (taken != null) {
1118      for (Enumeration<Instruction> e = taken.forwardRealInstrEnumerator(); e.hasMoreElements();) {
1119        Instruction s = e.nextElement();
1120        if (s.isBranch()) continue;
1121        Operand def = s.getDefs().nextElement();
1122        // if the register does not span a basic block, it is a temporary
1123        // that will now be dead
1124        if (def.asRegister().getRegister().spansBasicBlock()) {
1125          Instruction tempS = takenInstructions.get(s);
1126          RegisterOperand temp = (RegisterOperand) tempS.getDefs().nextElement();
1127          op = IRTools.getCondMoveOp(def.asRegister().getType());
1128          Instruction cmov =
1129              CondMove.create(op,
1130                              def.asRegister(),
1131                              tempVal1.copy(),
1132                              tempVal2.copy(),
1133                              cond.copy().asCondition(),
1134                              temp.copy(),
1135                              def.copy());
1136          takenMap.put(def.asRegister().getRegister(), cmov);
1137          cb.insertBefore(cmov);
1138        }
1139        s.remove();
1140      }
1141    }
1142    // For each register defined in the NOT-TAKEN branch, save a mapping to
1143    // the corresponding conditional move.
1144    HashMap<Register, Instruction> notTakenMap = new HashMap<Register, Instruction>();
1145    // Next handle the not taken branch.
1146    if (notTaken != null) {
1147      for (Enumeration<Instruction> e = notTaken.forwardRealInstrEnumerator(); e.hasMoreElements();) {
1148        Instruction s = e.nextElement();
1149        if (s.isBranch()) continue;
1150        Operand def = s.getDefs().nextElement();
1151        // if the register does not span a basic block, it is a temporary
1152        // that will now be dead
1153        if (def.asRegister().getRegister().spansBasicBlock()) {
1154          Instruction tempS = notTakenInstructions.get(s);
1155          RegisterOperand temp = (RegisterOperand) tempS.getDefs().nextElement();
1156
1157          Instruction prevCmov = takenMap.get(def.asRegister().getRegister());
1158          if (prevCmov != null) {
1159            // if this register was also defined in the taken branch, change
1160            // the previous cmov with a different 'False' Value
1161            CondMove.setFalseValue(prevCmov, temp.copy());
1162            notTakenMap.put(def.asRegister().getRegister(), prevCmov);
1163          } else {
1164            // create a new cmov instruction
1165            op = IRTools.getCondMoveOp(def.asRegister().getType());
1166            Instruction cmov =
1167                CondMove.create(op,
1168                                def.asRegister(),
1169                                tempVal1.copy(),
1170                                tempVal2.copy(),
1171                                cond.copy().asCondition(),
1172                                def.copy(),
1173                                temp.copy());
1174            cb.insertBefore(cmov);
1175            notTakenMap.put(def.asRegister().getRegister(), cmov);
1176          }
1177        }
1178        s.remove();
1179      }
1180    }
1181
1182    // Mutate the conditional branch into a GOTO.
1183    BranchOperand target = diamond.getBottom().makeJumpTarget();
1184    Goto.mutate(cb, GOTO, target);
1185
1186    // Delete a potential GOTO after cb.
1187    Instruction next = cb.nextInstructionInCodeOrder();
1188    if (next.operator() != BBEND) {
1189      next.remove();
1190    }
1191
1192    // Recompute the CFG.
1193    diamond.getTop().recomputeNormalOut(ir); // fix the CFG
1194  }
1195
1196  /**
1197   * Attempt to generate a boolean compare opcode from a conditional branch.
1198   *
1199   * <pre>
1200   * 1)   IF .. GOTO A          replaced by  BOOLEAN_CMP x=..
1201   *      x = 0
1202   *      GOTO B
1203   *   A: x = 1
1204   *   B: ...
1205   * </pre>
1206   *
1207   * <p> Precondition: <code>IfCmp.conforms(<i>cb</i>)</code>
1208   *
1209   *
1210   * @param ir governing IR
1211   * @param bb basic block of cb
1212   * @param cb conditional branch instruction
1213   * @param tb target block the branch instruction
1214   * @return {@code true} if and only if the transformation succeeds
1215   */
1216  private boolean generateBooleanCompare(IR ir, BasicBlock bb, Instruction cb, BasicBlock tb) {
1217
1218    if ((cb.operator() != INT_IFCMP) && (cb.operator() != REF_IFCMP)) {
1219      return false;
1220    }
1221    // make sure this is the last branch in the block
1222    if (cb.nextInstructionInCodeOrder().operator() != BBEND) {
1223      return false;
1224    }
1225    Operand val1 = IfCmp.getVal1(cb);
1226    Operand val2 = IfCmp.getVal2(cb);
1227    ConditionOperand condition = IfCmp.getCond(cb);
1228    // "not taken" path
1229    BasicBlock fb = cb.getBasicBlock().getNotTakenNextBlock();
1230    // make sure it's a diamond
1231    if (tb.getNumberOfNormalOut() != 1) {
1232      return false;
1233    }
1234    if (fb.getNumberOfNormalOut() != 1) {
1235      return false;
1236    }
1237    BasicBlock jb = fb.getNormalOut().nextElement();               // join block
1238    // make sure it's a diamond
1239    if (!tb.pointsOut(jb)) {
1240      return false;
1241    }
1242    Instruction ti = tb.firstRealInstruction();
1243    Instruction fi = fb.firstRealInstruction();
1244    // make sure the instructions in target blocks are either both moves
1245    // or both returns
1246    if (ti == null || fi == null) {
1247      return false;
1248    }
1249    if (ti.operator() != fi.operator()) {
1250      return false;
1251    }
1252    if (ti.operator() != RETURN && ti.operator() != INT_MOVE) {
1253      return false;
1254    }
1255    //
1256    // WARNING: This code is currently NOT exercised!
1257    //
1258    if (ti.operator() == RETURN) {
1259      // make sure each of the target blocks contains only one instruction
1260      if (ti != tb.lastRealInstruction()) {
1261        return false;
1262      }
1263      if (fi != fb.lastRealInstruction()) {
1264        return false;
1265      }
1266      Operand tr = Return.getVal(ti);
1267      Operand fr = Return.getVal(fi);
1268      // make sure we're returning constants
1269      if (!(tr instanceof IntConstantOperand) || !(fr instanceof IntConstantOperand)) {
1270        return false;
1271      }
1272      int tv = ((IntConstantOperand) tr).value;
1273      int fv = ((IntConstantOperand) fr).value;
1274      if (!((tv == 1 && fv == 0) || (tv == 1 && fv == 0))) {
1275        return false;
1276      }
1277      RegisterOperand t = ir.regpool.makeTemp(TypeReference.Boolean);
1278      // Cases 1) and 2)
1279      if (tv == 0) {
1280        condition = condition.flipCode();
1281      }
1282      booleanCompareHelper(cb, t, val1.copy(), val2.copy(), condition);
1283      cb.insertAfter(Return.create(RETURN, t.copyD2U()));
1284    } else {      // (ti.operator() == INT_MOVE)
1285      // make sure each of the target blocks only does the move
1286      if (ti != tb.lastRealInstruction() && ti.nextInstructionInCodeOrder().operator() != GOTO) {
1287        return false;
1288      }
1289      if (fi != fb.lastRealInstruction() && fi.nextInstructionInCodeOrder().operator() != GOTO) {
1290        return false;
1291      }
1292      RegisterOperand t = Move.getResult(ti);
1293      // make sure both moves are to the same register
1294      if (t.getRegister() != Move.getResult(fi).getRegister()) {
1295        return false;
1296      }
1297      Operand tr = Move.getVal(ti);
1298      Operand fr = Move.getVal(fi);
1299      // make sure we're assigning constants
1300      if (!(tr instanceof IntConstantOperand) || !(fr instanceof IntConstantOperand)) {
1301        return false;
1302      }
1303      int tv = ((IntConstantOperand) tr).value;
1304      int fv = ((IntConstantOperand) fr).value;
1305      if (!((tv == 1 && fv == 0) || (tv == 0 && fv == 1))) {
1306        return false;
1307      }
1308      // Cases 3) and 4)
1309      if (tv == 0) {
1310        condition = condition.flipCode();
1311      }
1312      booleanCompareHelper(cb, t.copyRO(), val1.copy(), val2.copy(), condition);
1313      Instruction next = cb.nextInstructionInCodeOrder();
1314      if (next.operator() == GOTO) {
1315        Goto.setTarget(next, jb.makeJumpTarget());
1316      } else {
1317        cb.insertAfter(jb.makeGOTO());
1318      }
1319    }
1320    // fixup CFG
1321    bb.deleteOut(tb);
1322    bb.deleteOut(fb);
1323    bb.insertOut(jb);           // Note: if we processed returns,
1324    // jb is the exit node.
1325    return true;
1326  }
1327}