/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.opt; import org.jikesrvm.ArchitectureSpecific.OPT_BURS_Debug; import org.jikesrvm.ArchitectureSpecific.OPT_BURS_STATE; import org.jikesrvm.ArchitectureSpecific.OPT_BURS_TreeNode; import org.jikesrvm.VM; import org.jikesrvm.compilers.opt.ir.OPT_AddressConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_BasicBlock; import org.jikesrvm.compilers.opt.ir.OPT_BranchOperand; import org.jikesrvm.compilers.opt.ir.OPT_IR; import org.jikesrvm.compilers.opt.ir.OPT_InlinedOsrTypeInfoOperand; import org.jikesrvm.compilers.opt.ir.OPT_Instruction; import org.jikesrvm.compilers.opt.ir.OPT_InstructionEnumeration; import org.jikesrvm.compilers.opt.ir.OPT_IntConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_LongConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_Operand; import org.jikesrvm.compilers.opt.ir.OPT_OperandEnumeration; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.CALL_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.OTHER_OPERAND_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.RETURN_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.SYSCALL_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.YIELDPOINT_OSR_opcode; import org.jikesrvm.compilers.opt.ir.OPT_RegisterOperand; /** * This class contains code for quick and dirty instruction selection * by forcing each instruction to be a tree and generating the trees in * the same input as the input LIR instructions. * This results in poor code quality, but can be done very quickly. * The intended purpose is to reduce compile time by doing quick and * dirty instruction selection for infrequntly executed basic blocks. * * @see OPT_BURS_STATE * @see OPT_BURS_TreeNode */ final class OPT_MinimalBURS extends OPT_BURS { /** * Create a BURS object for the given IR. * * @param IR the IR to translate from LIR to MIR. */ OPT_MinimalBURS(OPT_IR IR) { super(IR); } /** * Build BURS trees for dependence graph <code>bb</code>, label the trees, and * then generate MIR instructions based on the labeling. * @param bb The dependence graph. XXX Is this correct? */ public void invoke(OPT_BasicBlock bb) { OPT_BURS_STATE burs = new OPT_BURS_STATE(this); for (OPT_InstructionEnumeration e = bb.forwardRealInstrEnumerator(); e.hasMoreElements();) { OPT_Instruction s = e.next(); OPT_BURS_TreeNode tn = buildTree(s); burs.label(tn); OPT_BURS_STATE.mark(tn, /* goalnt */(byte) 1); generateTree(tn, burs); } } //////////////////////////////// // Implementation //////////////////////////////// /** * Build a BURS Tree for each OPT_Instruction. * Complete BURS trees by adding leaf nodes as needed, and * creating tree edges by calling insertChild1() or insertChild2() * This step is also where we introduce intermediate tree nodes for * any LIR instruction that has > 2 "real" operands e.g., a CALL. * * @param s The instruction for which a tree must be built */ private OPT_BURS_TreeNode buildTree(OPT_Instruction s) { OPT_BURS_TreeNode root = new OPT_BURS_TreeNode(new OPT_DepGraphNode(s)); OPT_BURS_TreeNode cur = root; for (OPT_OperandEnumeration uses = s.getUses(); uses.hasMoreElements();) { OPT_Operand op = uses.next(); if (op == null) continue; // Set child = OPT_BURS_TreeNode for operand op OPT_BURS_TreeNode child; if (op instanceof OPT_RegisterOperand) { if (op.asRegister().getRegister().isValidation()) continue; child = Register; } else if (op instanceof OPT_IntConstantOperand) { child = new OPT_BURS_IntConstantTreeNode(((OPT_IntConstantOperand) op).value); } else if (op instanceof OPT_LongConstantOperand) { child = LongConstant; } else if (op instanceof OPT_AddressConstantOperand) { child = AddressConstant; } else if (op instanceof OPT_BranchOperand && s.isCall()) { child = BranchTarget; } else if (op instanceof OPT_InlinedOsrTypeInfoOperand && s.isYieldPoint()) { child = NullTreeNode; } else { continue; } // Attach child as child of cur_parent in correct position if (cur.child1 == null) { cur.child1 = child; } else if (cur.child2 == null) { cur.child2 = child; } else { // Create auxiliary node so as to represent // a instruction with arity > 2 in a binary tree. OPT_BURS_TreeNode child1 = cur.child2; OPT_BURS_TreeNode aux = new OPT_BURS_TreeNode(OTHER_OPERAND_opcode); cur.child2 = aux; cur = aux; cur.child1 = child1; cur.child2 = child; } } // patch for calls & return switch (s.getOpcode()) { case CALL_opcode: case SYSCALL_opcode: case YIELDPOINT_OSR_opcode: if (cur.child2 == null) { cur.child2 = NullTreeNode; } // fall through case RETURN_opcode: if (cur.child1 == null) { cur.child1 = NullTreeNode; } } return root; } // Generate code for a single tree root. private void generateTree(OPT_BURS_TreeNode k, OPT_BURS_STATE burs) { OPT_BURS_TreeNode child1 = k.child1; OPT_BURS_TreeNode child2 = k.child2; if (child1 != null) { if (child2 != null) { // k has two children; use register labeling to // determine order that minimizes register pressure if (k.isSuperNodeRoot()) { byte act = OPT_BURS_STATE.action[k.rule(k.getNonTerminal())]; if ((act & OPT_BURS_STATE.RIGHT_CHILD_FIRST) != 0) { // rule selected forces order of evaluation generateTree(child2, burs); generateTree(child1, burs); } else { generateTree(child1, burs); generateTree(child2, burs); } } else { generateTree(child1, burs); generateTree(child2, burs); } } else { generateTree(child1, burs); } } else if (child2 != null) { generateTree(child2, burs); } if (k.isSuperNodeRoot()) { int nonterminal = k.getNonTerminal(); int rule = k.rule(nonterminal); burs.code(k, nonterminal, rule); if (DEBUG) VM.sysWrite(k + " " + OPT_BURS_Debug.string[rule] + "\n"); } } }