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.lir2mir;
014
015import org.jikesrvm.VM;
016import org.jikesrvm.compilers.opt.ir.BasicBlock;
017import org.jikesrvm.compilers.opt.ir.IR;
018import org.jikesrvm.compilers.opt.ir.Instruction;
019import static org.jikesrvm.compilers.opt.ir.Operators.ADDRESS_CONSTANT_opcode;
020import static org.jikesrvm.compilers.opt.ir.Operators.BRANCH_TARGET_opcode;
021import static org.jikesrvm.compilers.opt.ir.Operators.LONG_CONSTANT_opcode;
022import static org.jikesrvm.compilers.opt.ir.Operators.NULL_opcode;
023import static org.jikesrvm.compilers.opt.ir.Operators.REGISTER_opcode;
024
025/**
026 * A few common utilities used for invoking BURS tree-pattern matching
027 * to do instruction selection.  The interesting code is in the
028 * subclasses of this class.
029 */
030public abstract class BURS {
031
032  public static final boolean DEBUG = false;
033
034  protected final AbstractBURS_TreeNode NullTreeNode = AbstractBURS_TreeNode.create(NULL_opcode);
035  protected final AbstractBURS_TreeNode LongConstant = AbstractBURS_TreeNode.create(LONG_CONSTANT_opcode);
036  protected final AbstractBURS_TreeNode AddressConstant = AbstractBURS_TreeNode.create(ADDRESS_CONSTANT_opcode);
037  protected final AbstractBURS_TreeNode Register = AbstractBURS_TreeNode.create(REGISTER_opcode);
038  protected final AbstractBURS_TreeNode BranchTarget = AbstractBURS_TreeNode.create(BRANCH_TARGET_opcode);
039
040  BURS(IR ir) {
041    this.ir = ir;
042    NullTreeNode.setNumRegisters(0);
043    LongConstant.setNumRegisters(0);
044    AddressConstant.setNumRegisters(0);
045    Register.setNumRegisters(1);
046    BranchTarget.setNumRegisters(0);
047  }
048
049  public final IR ir;
050  protected Instruction lastInstr;
051
052  /** @return the architecture dependent BURS coder */
053  BURS_StateCoder makeCoder() {
054    if (VM.BuildForIA32) {
055      if (VM.BuildFor32Addr) {
056        return new org.jikesrvm.compilers.opt.lir2mir.ia32_32.BURS_STATE(this);
057      } else {
058        return new org.jikesrvm.compilers.opt.lir2mir.ia32_64.BURS_STATE(this);
059      }
060    } else {
061      if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC);
062      if (VM.BuildFor32Addr) {
063        return new org.jikesrvm.compilers.opt.lir2mir.ppc_32.BURS_STATE(this);
064      } else {
065        return new org.jikesrvm.compilers.opt.lir2mir.ppc_64.BURS_STATE(this);
066      }
067    }
068  }
069
070  /**
071   * Recursively labels the tree with costs.
072   * @param tn the tree to label
073   */
074  static void label(AbstractBURS_TreeNode tn) {
075    if (VM.BuildForIA32) {
076      if (VM.BuildFor32Addr) {
077        org.jikesrvm.compilers.opt.lir2mir.ia32_32.BURS_STATE.label(tn);
078      } else {
079        org.jikesrvm.compilers.opt.lir2mir.ia32_64.BURS_STATE.label(tn);
080      }
081    } else {
082      if (VM.BuildFor32Addr) {
083        org.jikesrvm.compilers.opt.lir2mir.ppc_32.BURS_STATE.label(tn);
084      } else {
085        org.jikesrvm.compilers.opt.lir2mir.ppc_64.BURS_STATE.label(tn);
086      }
087    }
088  }
089
090  /**
091   * Traverses the tree, marking the non-terminal to be generated for each
092   * sub-tree.
093   *
094   * @param tn the tree to traverse
095   * @param goalnt the goal
096   */
097  static void mark(AbstractBURS_TreeNode tn, byte goalnt) {
098    if (VM.BuildForIA32) {
099      if (VM.BuildFor32Addr) {
100        org.jikesrvm.compilers.opt.lir2mir.ia32_32.BURS_STATE.mark(tn, goalnt);
101      } else {
102        org.jikesrvm.compilers.opt.lir2mir.ia32_64.BURS_STATE.mark(tn, goalnt);
103      }
104    } else {
105      if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC);
106      if (VM.BuildFor32Addr) {
107        org.jikesrvm.compilers.opt.lir2mir.ppc_32.BURS_STATE.mark(tn, goalnt);
108      } else {
109        org.jikesrvm.compilers.opt.lir2mir.ppc_64.BURS_STATE.mark(tn, goalnt);
110      }
111    }
112  }
113
114  /**
115   *  @param rule the rule's number
116   *  @return the action associated with a rule
117   */
118  static byte action(int rule) {
119    if (VM.BuildForIA32) {
120      if (VM.BuildFor32Addr) {
121        return org.jikesrvm.compilers.opt.lir2mir.ia32_32.BURS_STATE.action(rule);
122      } else {
123        return org.jikesrvm.compilers.opt.lir2mir.ia32_64.BURS_STATE.action(rule);
124      }
125    } else {
126      if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC);
127      if (VM.BuildFor32Addr) {
128        return org.jikesrvm.compilers.opt.lir2mir.ppc_32.BURS_STATE.action(rule);
129      } else {
130        return org.jikesrvm.compilers.opt.lir2mir.ppc_64.BURS_STATE.action(rule);
131      }
132    }
133  }
134
135  /**
136   * Dumps the tree for debugging.
137   * @param tn the root of the tree to be dumped
138   */
139  static void dumpTree(AbstractBURS_TreeNode tn) {
140    if (VM.BuildForIA32) {
141      if (VM.BuildFor32Addr) {
142        org.jikesrvm.compilers.opt.lir2mir.ia32_32.BURS_STATE.dumpTree(tn);
143      } else {
144        org.jikesrvm.compilers.opt.lir2mir.ia32_64.BURS_STATE.dumpTree(tn);
145      }
146    } else {
147      if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC);
148      if (VM.BuildFor32Addr) {
149        org.jikesrvm.compilers.opt.lir2mir.ppc_32.BURS_STATE.dumpTree(tn);
150      } else {
151        org.jikesrvm.compilers.opt.lir2mir.ppc_64.BURS_STATE.dumpTree(tn);
152      }
153    }
154  }
155
156  /**
157   * @param rule the rule's number
158   * @return debug string for a particular rule
159   */
160  static String debug(int rule) {
161    if (VM.BuildForIA32) {
162      if (VM.BuildFor32Addr) {
163        return org.jikesrvm.compilers.opt.lir2mir.ia32_32.BURS_Debug.string[rule];
164      } else {
165        return org.jikesrvm.compilers.opt.lir2mir.ia32_64.BURS_Debug.string[rule];
166      }
167    } else {
168      if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC);
169      if (VM.BuildFor32Addr) {
170        return org.jikesrvm.compilers.opt.lir2mir.ppc_32.BURS_Debug.string[rule];
171      } else {
172        return org.jikesrvm.compilers.opt.lir2mir.ppc_64.BURS_Debug.string[rule];
173      }
174    }
175  }
176
177  /**
178   * Prepares for conversion of a block. This method must be called before
179   * using an invoke method from the subclasses.
180   *
181   * @param bb a basic block
182   */
183  final void prepareForBlock(BasicBlock bb) {
184    if (DEBUG) {
185      VM.sysWrite("FINAL LIR\n");
186      bb.printExtended();
187    }
188    lastInstr = bb.firstInstruction();
189  }
190
191  /**
192   * Finalizes a block. This method must be called after
193   * using an invoke method for all non-empty blocks.
194   *
195   * @param bb a basic block
196   */
197  final void finalizeBlock(BasicBlock bb) {
198    lastInstr.BURS_backdoor_linkWithNext(bb.lastInstruction());
199    lastInstr = null;
200    if (DEBUG) {
201      VM.sysWrite("INITIAL MIR\n");
202      bb.printExtended();
203    }
204  }
205
206  /**
207   * Appends an instruction, i.e. emits an MIR instruction.
208   *
209   * @param instruction the instruction to emit
210   */
211  public final void append(Instruction instruction) {
212    lastInstr.BURS_backdoor_linkWithNext(instruction);
213    lastInstr = instruction;
214  }
215}
216
217