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 java.util.Enumeration;
016    
017    import org.jikesrvm.VM;
018    import org.jikesrvm.compilers.opt.ir.IfCmp;
019    import org.jikesrvm.compilers.opt.ir.Label;
020    import org.jikesrvm.compilers.opt.ir.BasicBlock;
021    import org.jikesrvm.compilers.opt.ir.Instruction;
022    import org.jikesrvm.compilers.opt.ir.operand.BranchOperand;
023    
024    /**
025     * This class represents a diamond (if-then-else) structure in the
026     * control-flow graph.
027     */
028    final class Diamond {
029      /**
030       * The top of the diamond
031       */
032      private final BasicBlock top;
033    
034      /**
035       * The bottom of the diamond
036       */
037      private final BasicBlock bottom;
038    
039      /**
040       * The "taken" branch of the diamond (might be null)
041       */
042      private final BasicBlock taken;
043    
044      /**
045       * The "not-taken" branch of the diamond (might be null)
046       */
047      private final BasicBlock notTaken;
048    
049      /**
050       * The top of the diamond
051       */
052      BasicBlock getTop() { return top; }
053    
054      /**
055       * The bottom of the diamond
056       */
057      BasicBlock getBottom() { return bottom; }
058    
059      /**
060       * The "taken" branch of the diamond (might be null)
061       */
062      BasicBlock getTaken() { return taken;}
063    
064      /**
065       * The "not-taken" branch of the diamond (might be null)
066       */
067      BasicBlock getNotTaken() { return notTaken; }
068    
069      Diamond(BasicBlock top, BasicBlock taken, BasicBlock notTaken, BasicBlock bottom) {
070        this.top = top;
071        this.taken = taken;
072        this.notTaken = notTaken;
073        this.bottom = bottom;
074      }
075    
076      /**
077       * See if bb is the root of a diamond.  If so, return an Diamond
078       * representing the structure.
079       *
080       * @return a structure representing the diamond.  null if not
081       * applicable.
082       */
083      static Diamond buildDiamond(BasicBlock bb) {
084        if (bb.getNumberOfNormalOut() != 2) return null;
085    
086        // Identify the two out nodes from bb.
087        Enumeration<BasicBlock> outNodes = bb.getNormalOut();
088        BasicBlock out1 = outNodes.nextElement();
089        BasicBlock out2 = outNodes.nextElement();
090        int out1In = out1.getNumberOfIn();
091        int out2In = out2.getNumberOfIn();
092    
093        if (out1In == 1 && out2In == 1) {
094          // look for the case where the diamond has four non-empty blocks.
095          if (out1.getNumberOfNormalOut() == 1 && out2.getNumberOfNormalOut() == 1) {
096            BasicBlock b1 = out1.getNormalOut().nextElement();
097            BasicBlock b2 = out2.getNormalOut().nextElement();
098            if (b1 == b2) {
099              return fourElementDiamond(bb, out1, out2, b1);
100            }
101          }
102        } else if (out1In == 1) {
103          // check for a 3-element diamond
104          if (out1.getNumberOfNormalOut() == 1) {
105            BasicBlock b1 = out1.getNormalOut().nextElement();
106            if (b1 == out2) {
107              return threeElementDiamond(bb, out1, out2);
108            }
109          }
110        } else if (out2In == 1) {
111          // check for a 3-element diamond
112          if (out2.getNumberOfNormalOut() == 1) {
113            BasicBlock b2 = out2.getNormalOut().nextElement();
114            if (b2 == out1) {
115              return threeElementDiamond(bb, out2, out1);
116            }
117          }
118        }
119        // didn't find a diamond
120        return null;
121      }
122    
123      /**
124       * Given that four blocks form a diamond, return the correct structure.
125       */
126      private static Diamond fourElementDiamond(BasicBlock top, BasicBlock left, BasicBlock right,
127                                                    BasicBlock bottom) {
128    
129        Instruction cb = top.firstBranchInstruction();
130        // for now we only support IfCmp diamonds.
131        if (VM.VerifyAssertions) VM._assert(IfCmp.conforms(cb));
132    
133        BranchOperand takenTarget = IfCmp.getTarget(cb);
134        if (Label.getBlock(takenTarget.target).block == left) {
135          return new Diamond(top, left, right, bottom);
136        } else {
137          return new Diamond(top, right, left, bottom);
138        }
139      }
140    
141      /**
142       * Given that three blocks form a diamond, return the correct structure.
143       */
144      private static Diamond threeElementDiamond(BasicBlock top, BasicBlock side, BasicBlock bottom) {
145    
146        Instruction cb = top.firstBranchInstruction();
147        // for now we only support IfCmp diamonds.
148        if (VM.VerifyAssertions) VM._assert(IfCmp.conforms(cb));
149    
150        BranchOperand takenTarget = IfCmp.getTarget(cb);
151        if (Label.getBlock(takenTarget.target).block == side) {
152          return new Diamond(top, side, null, bottom);
153        } else {
154          return new Diamond(top, null, side, bottom);
155        }
156      }
157    
158      /**
159       * Return a string representation.
160       */
161      @Override
162      public String toString() {
163        return "[" + top + "," + taken + "," + notTaken + "," + bottom + "]";
164      }
165    }