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.regalloc.ia32;
014
015import static org.jikesrvm.compilers.opt.ir.IRTools.IC;
016import static org.jikesrvm.compilers.opt.ir.IRTools.LC;
017import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ADD;
018import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOV;
019import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOVSXQ__W;
020import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SHL;
021import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IMMQ_MOV;
022
023import org.jikesrvm.VM;
024import org.jikesrvm.classloader.TypeReference;
025import org.jikesrvm.compilers.opt.OptOptions;
026import org.jikesrvm.compilers.opt.driver.CompilerPhase;
027import org.jikesrvm.compilers.opt.ir.IR;
028import org.jikesrvm.compilers.opt.ir.Instruction;
029import org.jikesrvm.compilers.opt.ir.ia32.MIR_BinaryAcc;
030import org.jikesrvm.compilers.opt.ir.ia32.MIR_Move;
031import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
032import org.jikesrvm.compilers.opt.ir.operand.MemoryOperand;
033import org.jikesrvm.compilers.opt.ir.operand.Operand;
034import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
035import org.jikesrvm.util.Bits;
036
037/**
038 * Processes memory operands with a displacement that doesn't fit
039 * into 32 bits. This is only necessary on x64.
040 */
041public class RewriteMemoryOperandsWithOversizedDisplacements extends CompilerPhase {
042
043  @Override
044  public final boolean shouldPerform(OptOptions options) {
045    return VM.BuildFor64Addr;
046  }
047
048  @Override
049  public String getName() {
050    return "Rewrite MemoryOperands with 64-bit displacements";
051  }
052
053  @Override
054  public void perform(IR ir) {
055    for (Instruction inst = ir.firstInstructionInCodeOrder(); inst != null; inst =
056        inst.nextInstructionInCodeOrder()) {
057      for (int i = 0; i < inst.getNumberOfOperands(); i++) {
058        Operand op = inst.getOperand(i);
059        if (op instanceof MemoryOperand) {
060          MemoryOperand mo = (MemoryOperand)op;
061          disp64MemOperandConversion(ir, inst, mo);
062        }
063      }
064    }
065  }
066
067  @Override
068  public CompilerPhase newExecution(IR ir) {
069    return this;
070  }
071
072  private static void disp64MemOperandConversion(IR ir, Instruction inst, MemoryOperand mo) {
073    if (!mo.disp.isZero() && !Bits.fits(mo.disp, 32)) {
074      RegisterOperand effectiveAddress = ir.regpool.makeTempLong();
075      RegisterOperand temp = null;
076      inst.insertBefore(MIR_Move.create(IMMQ_MOV, effectiveAddress, LC(mo.disp.toLong())));
077      if (mo.index != null) {
078         if (mo.scale != 0) {
079           temp = ir.regpool.makeTempLong();
080           if (mo.index.getType() != TypeReference.Long) {
081             inst.insertBefore(MIR_Move.create(IA32_MOVSXQ__W, temp, mo.index));
082           } else {
083             inst.insertBefore(MIR_Move.create(IA32_MOV, temp, mo.index));
084           }
085           inst.insertBefore(MIR_BinaryAcc.create(IA32_SHL, temp, IC(mo.scale)));
086           inst.insertBefore(MIR_BinaryAcc.create(IA32_ADD, effectiveAddress, temp));
087         } else {
088           if (mo.index.getType() != TypeReference.Long) {
089             temp = ir.regpool.makeTempLong();
090             inst.insertBefore(MIR_Move.create(IA32_MOVSXQ__W, temp, mo.index));
091             inst.insertBefore(MIR_BinaryAcc.create(IA32_ADD, effectiveAddress, temp));
092           } else {
093             inst.insertBefore(MIR_BinaryAcc.create(IA32_ADD, effectiveAddress, mo.index));
094           }
095         }
096      }
097      if (mo.base != null) {
098        inst.insertBefore(MIR_BinaryAcc.create(IA32_ADD, effectiveAddress, mo.base));
099      }
100      MemoryOperand newMo = MemoryOperand.I(effectiveAddress, mo.size, null != mo.loc ? (LocationOperand)mo.loc.copy() : null,
101          mo.guard != null ? mo.guard.copy() : null);
102      inst.replaceOperand(mo, newMo);
103    }
104  }
105
106}