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.lir2mir;
014    
015    import java.util.Enumeration;
016    
017    import org.jikesrvm.ArchitectureSpecificOpt.BURS_Debug;
018    import org.jikesrvm.ArchitectureSpecificOpt.BURS_STATE;
019    import org.jikesrvm.ArchitectureSpecificOpt.BURS_TreeNode;
020    import org.jikesrvm.VM;
021    import org.jikesrvm.compilers.opt.depgraph.DepGraphNode;
022    import org.jikesrvm.compilers.opt.ir.BasicBlock;
023    import org.jikesrvm.compilers.opt.ir.Instruction;
024    import org.jikesrvm.compilers.opt.ir.IR;
025    import static org.jikesrvm.compilers.opt.ir.Operators.CALL_opcode;
026    import static org.jikesrvm.compilers.opt.ir.Operators.OTHER_OPERAND_opcode;
027    import static org.jikesrvm.compilers.opt.ir.Operators.RETURN_opcode;
028    import static org.jikesrvm.compilers.opt.ir.Operators.SYSCALL_opcode;
029    import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_OSR_opcode;
030    import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand;
031    import org.jikesrvm.compilers.opt.ir.operand.BranchOperand;
032    import org.jikesrvm.compilers.opt.ir.operand.InlinedOsrTypeInfoOperand;
033    import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
034    import org.jikesrvm.compilers.opt.ir.operand.LongConstantOperand;
035    import org.jikesrvm.compilers.opt.ir.operand.Operand;
036    import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
037    
038    /**
039     * This class contains code for quick and dirty instruction selection
040     * by forcing each instruction to be a tree and generating the trees in
041     * the same input as the input LIR instructions.
042     * This results in poor code quality, but can be done very quickly.
043     * The intended purpose is to reduce compile time by doing quick and
044     * dirty instruction selection for infrequently executed basic blocks.
045     *
046     * @see BURS_STATE
047     * @see BURS_TreeNode
048     */
049    final class MinimalBURS extends BURS {
050    
051      /**
052       * Create a BURS object for the given IR.
053       *
054       * @param ir the IR to translate from LIR to MIR.
055       */
056      MinimalBURS(IR ir) {
057        super(ir);
058      }
059    
060      /**
061       * Build BURS trees for dependence graph <code>bb</code>, label the trees, and
062       * then generate MIR instructions based on the labeling.
063       * @param bb   The dependence graph.   XXX Is this correct?
064       */
065      public void invoke(BasicBlock bb) {
066        BURS_STATE burs = new BURS_STATE(this);
067        for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements();) {
068          Instruction s = e.nextElement();
069          BURS_TreeNode tn = buildTree(s);
070          burs.label(tn);
071          BURS_STATE.mark(tn, /* goalnt */(byte) 1);
072          generateTree(tn, burs);
073        }
074      }
075    
076      ////////////////////////////////
077      // Implementation
078      ////////////////////////////////
079    
080      /**
081       * Build a BURS Tree for each Instruction.
082       * Complete BURS trees by adding leaf nodes as needed, and
083       * creating tree edges by calling insertChild1() or insertChild2()
084       * This step is also where we introduce intermediate tree nodes for
085       * any LIR instruction that has > 2 "real" operands e.g., a CALL.
086       *
087       * @param s The instruction for which a tree must be built
088       */
089      private BURS_TreeNode buildTree(Instruction s) {
090    
091        BURS_TreeNode root = new BURS_TreeNode(new DepGraphNode(s));
092        BURS_TreeNode cur = root;
093        for (Enumeration<Operand> uses = s.getUses(); uses.hasMoreElements();) {
094          Operand op = uses.nextElement();
095          if (op == null) continue;
096    
097          // Set child = BURS_TreeNode for operand op
098          BURS_TreeNode child;
099          if (op instanceof RegisterOperand) {
100            if (op.asRegister().getRegister().isValidation()) continue;
101            child = Register;
102          } else if (op instanceof IntConstantOperand) {
103            child = new BURS_IntConstantTreeNode(((IntConstantOperand) op).value);
104          } else if (op instanceof LongConstantOperand) {
105            child = LongConstant;
106          } else if (op instanceof AddressConstantOperand) {
107            child = AddressConstant;
108          } else if (op instanceof BranchOperand && s.isCall()) {
109            child = BranchTarget;
110          } else if (op instanceof InlinedOsrTypeInfoOperand && s.isYieldPoint()) {
111            child = NullTreeNode;
112          } else {
113            continue;
114          }
115    
116          // Attach child as child of cur_parent in correct position
117          if (cur.child1 == null) {
118            cur.child1 = child;
119          } else if (cur.child2 == null) {
120            cur.child2 = child;
121          } else {
122            // Create auxiliary node so as to represent
123            // a instruction with arity > 2 in a binary tree.
124            BURS_TreeNode child1 = cur.child2;
125            BURS_TreeNode aux = new BURS_TreeNode(OTHER_OPERAND_opcode);
126            cur.child2 = aux;
127            cur = aux;
128            cur.child1 = child1;
129            cur.child2 = child;
130          }
131        }
132    
133        // patch for calls & return
134        switch (s.getOpcode()) {
135          case CALL_opcode:
136          case SYSCALL_opcode:
137          case YIELDPOINT_OSR_opcode:
138            if (cur.child2 == null) {
139              cur.child2 = NullTreeNode;
140            }
141            // fall through
142          case RETURN_opcode:
143            if (cur.child1 == null) {
144              cur.child1 = NullTreeNode;
145            }
146        }
147        return root;
148      }
149    
150    
151    
152      /**
153       * Generates code for a single tree root.
154       * @param k the root to start generation at
155       * @param burs
156       */
157      private void generateTree(BURS_TreeNode k, BURS_STATE burs) {
158        BURS_TreeNode child1 = k.child1;
159        BURS_TreeNode child2 = k.child2;
160        if (child1 != null) {
161          if (child2 != null) {
162            // k has two children; use register labeling to
163            // determine order that minimizes register pressure
164            if (k.isSuperNodeRoot()) {
165              byte act = BURS_STATE.action[k.rule(k.getNonTerminal())];
166              if ((act & BURS_STATE.RIGHT_CHILD_FIRST) != 0) {
167                // rule selected forces order of evaluation
168                generateTree(child2, burs);
169                generateTree(child1, burs);
170              } else {
171                generateTree(child1, burs);
172                generateTree(child2, burs);
173              }
174            } else {
175              generateTree(child1, burs);
176              generateTree(child2, burs);
177            }
178          } else {
179            generateTree(child1, burs);
180          }
181        } else if (child2 != null) {
182          generateTree(child2, burs);
183        }
184    
185        if (k.isSuperNodeRoot()) {
186          int nonterminal = k.getNonTerminal();
187          int rule = k.rule(nonterminal);
188          burs.code(k, nonterminal, rule);
189          if (DEBUG) VM.sysWrite(k + " " + BURS_Debug.string[rule] + "\n");
190        }
191      }
192    }