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.ia32;
014
015import static org.jikesrvm.compilers.opt.driver.OptConstants.IA32_REF_LOAD;
016import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.MATERIALIZE_FP_CONSTANT;
017
018import org.jikesrvm.VM;
019import org.jikesrvm.classloader.TypeReference;
020import org.jikesrvm.compilers.opt.OptimizingCompilerException;
021import org.jikesrvm.compilers.opt.ir.Binary;
022import org.jikesrvm.compilers.opt.ir.IR;
023import org.jikesrvm.compilers.opt.ir.Instruction;
024import org.jikesrvm.compilers.opt.ir.Load;
025import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand;
026import org.jikesrvm.compilers.opt.ir.operand.ClassConstantOperand;
027import org.jikesrvm.compilers.opt.ir.operand.CodeConstantOperand;
028import org.jikesrvm.compilers.opt.ir.operand.DoubleConstantOperand;
029import org.jikesrvm.compilers.opt.ir.operand.FloatConstantOperand;
030import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
031import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
032import org.jikesrvm.compilers.opt.ir.operand.LongConstantOperand;
033import org.jikesrvm.compilers.opt.ir.operand.NullConstantOperand;
034import org.jikesrvm.compilers.opt.ir.operand.ObjectConstantOperand;
035import org.jikesrvm.compilers.opt.ir.operand.Operand;
036import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
037import org.jikesrvm.compilers.opt.ir.operand.StringConstantOperand;
038import org.jikesrvm.compilers.opt.ir.operand.TIBConstantOperand;
039import org.jikesrvm.runtime.Magic;
040import org.jikesrvm.runtime.Statics;
041import org.vmmagic.unboxed.Offset;
042import org.vmmagic.unboxed.Word;
043
044/**
045 * Normalize the use of constants in the LIR
046 * to match the patterns supported in LIR2MIR.rules
047 */
048public abstract class NormalizeConstants {
049
050  /**
051   * Only thing we do for IA32 is to restrict the usage of
052   * String, Float, and Double constants.  The rules are prepared
053   * to deal with everything else.
054   *
055   * @param ir IR to normalize
056   */
057  public static void perform(IR ir) {
058    for (Instruction s = ir.firstInstructionInCodeOrder(); s != null; s = s.nextInstructionInCodeOrder()) {
059
060      // Get 'large' constants into a form the the BURS rules are
061      // prepared to deal with.
062      // Constants can't appear as defs, so only scan the uses.
063      //
064      int numUses = s.getNumberOfUses();
065      if (numUses > 0) {
066        int numDefs = s.getNumberOfDefs();
067        for (int idx = numDefs; idx < numUses + numDefs; idx++) {
068          Operand use = s.getOperand(idx);
069          if (use != null) {
070            if (use instanceof ObjectConstantOperand) {
071              ObjectConstantOperand oc = (ObjectConstantOperand) use;
072              if (oc.isMovableObjectConstant()) {
073                RegisterOperand rop = ir.regpool.makeTemp(use.getType());
074                Operand jtoc = ir.regpool.makeJTOCOp();
075                Offset offset = oc.offset;
076                if (offset.isZero()) {
077                  if (use instanceof StringConstantOperand) {
078                    throw new OptimizingCompilerException("String constant w/o valid JTOC offset");
079                  } else if (use instanceof ClassConstantOperand) {
080                    throw new OptimizingCompilerException("Class constant w/o valid JTOC offset");
081                  }
082                  offset = Offset.fromIntSignExtend(Statics.findOrCreateObjectLiteral(oc.value));
083                }
084                LocationOperand loc = new LocationOperand(offset);
085                s.insertBefore(Load.create(IA32_REF_LOAD, rop, jtoc, wordOperandForReference(offset.toWord()), loc));
086                s.putOperand(idx, rop.copyD2U());
087              } else {
088                // Ensure object is in JTOC to keep it alive
089                Statics.findOrCreateObjectLiteral(oc.value);
090                s.putOperand(idx, wordOperandForReference(Magic.objectAsAddress(oc.value).toWord()));
091              }
092            } else if (use instanceof DoubleConstantOperand) {
093              RegisterOperand rop = ir.regpool.makeTemp(TypeReference.Double);
094              Operand jtoc = ir.regpool.makeJTOCOp();
095              DoubleConstantOperand dc = (DoubleConstantOperand) use.copy();
096              if (dc.offset.isZero()) {
097                dc.offset =
098                    Offset.fromIntSignExtend(Statics.findOrCreateLongSizeLiteral(Double.doubleToLongBits(dc.value)));
099              }
100              s.insertBefore(Binary.create(MATERIALIZE_FP_CONSTANT, rop, jtoc, dc));
101              s.putOperand(idx, rop.copyD2U());
102            } else if (use instanceof FloatConstantOperand) {
103              RegisterOperand rop = ir.regpool.makeTemp(TypeReference.Float);
104              Operand jtoc = ir.regpool.makeJTOCOp();
105              FloatConstantOperand fc = (FloatConstantOperand) use.copy();
106              if (fc.offset.isZero()) {
107                fc.offset =
108                    Offset.fromIntSignExtend(Statics.findOrCreateIntSizeLiteral(Float.floatToIntBits(fc.value)));
109              }
110              s.insertBefore(Binary.create(MATERIALIZE_FP_CONSTANT, rop, jtoc, fc));
111              s.putOperand(idx, rop.copyD2U());
112            } else if (use instanceof NullConstantOperand) {
113              s.putOperand(idx, wordOperandForReference(Word.zero()));
114            } else if (use instanceof AddressConstantOperand) {
115              s.putOperand(idx, wordOperandForReference(((AddressConstantOperand) use).value.toWord()));
116            } else if (use instanceof TIBConstantOperand) {
117              RegisterOperand rop = ir.regpool.makeTemp(TypeReference.TIB);
118              Operand jtoc = ir.regpool.makeJTOCOp();
119              Offset offset = ((TIBConstantOperand) use).value.getTibOffset();
120              LocationOperand loc = new LocationOperand(offset);
121              s.insertBefore(Load.create(IA32_REF_LOAD, rop, jtoc, wordOperandForReference(offset.toWord()), loc));
122              s.putOperand(idx, rop.copyD2U());
123            } else if (use instanceof CodeConstantOperand) {
124              RegisterOperand rop = ir.regpool.makeTemp(TypeReference.CodeArray);
125              Operand jtoc = ir.regpool.makeJTOCOp();
126              Offset offset = ((CodeConstantOperand) use).value.findOrCreateJtocOffset();
127              LocationOperand loc = new LocationOperand(offset);
128              s.insertBefore(Load.create(IA32_REF_LOAD, rop, jtoc, wordOperandForReference(offset.toWord()), loc));
129              s.putOperand(idx, rop.copyD2U());
130            }
131          }
132        }
133      }
134    }
135  }
136
137  private static Operand wordOperandForReference(Word w) {
138    if (VM.BuildFor64Addr) {
139      return new LongConstantOperand(w.toLong(), true);
140    } else {
141      return new IntConstantOperand(w.toInt());
142    }
143  }
144
145}