/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* 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/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt.regalloc.ia32;
import static org.jikesrvm.compilers.opt.ir.IRTools.IC;
import static org.jikesrvm.compilers.opt.ir.IRTools.LC;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_ADD;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOV;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOVSXDQ;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOVSXQ__B;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_MOVSXQ__W;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_SHL;
import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IMMQ_MOV;
import org.jikesrvm.VM;
import org.jikesrvm.classloader.TypeReference;
import org.jikesrvm.compilers.opt.OptOptions;
import org.jikesrvm.compilers.opt.driver.CompilerPhase;
import org.jikesrvm.compilers.opt.ir.IR;
import org.jikesrvm.compilers.opt.ir.Instruction;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_BinaryAcc;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_Move;
import org.jikesrvm.compilers.opt.ir.ia32.MIR_Unary;
import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
import org.jikesrvm.compilers.opt.ir.operand.MemoryOperand;
import org.jikesrvm.compilers.opt.ir.operand.Operand;
import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
import org.jikesrvm.util.Bits;
/**
* Processes memory operands with a displacement that doesn't fit
* into 32 bits. This is only necessary on x64.
*/
public class RewriteMemoryOperandsWithOversizedDisplacements extends CompilerPhase {
@Override
public final boolean shouldPerform(OptOptions options) {
return VM.BuildFor64Addr;
}
@Override
public String getName() {
return "Rewrite MemoryOperands with 64-bit displacements";
}
@Override
public void perform(IR ir) {
for (Instruction inst = ir.firstInstructionInCodeOrder(); inst != null; inst =
inst.nextInstructionInCodeOrder()) {
for (int i = 0; i < inst.getNumberOfOperands(); i++) {
Operand op = inst.getOperand(i);
if (op instanceof MemoryOperand) {
MemoryOperand mo = (MemoryOperand)op;
disp64MemOperandConversion(ir, inst, mo);
}
}
}
}
@Override
public CompilerPhase newExecution(IR ir) {
return this;
}
private static void disp64MemOperandConversion(IR ir, Instruction inst, MemoryOperand mo) {
if (!mo.disp.isZero() && !Bits.fits(mo.disp, 32)) {
RegisterOperand effectiveAddress = ir.regpool.makeTempLong();
RegisterOperand temp = null;
inst.insertBefore(MIR_Move.create(IMMQ_MOV, effectiveAddress, LC(mo.disp.toLong())));
if (mo.index != null) {
if (mo.scale != 0) {
temp = ir.regpool.makeTempLong();
TypeReference indexType = mo.index.getType();
if (indexType.isLongType() || indexType.isWordLikeType()) {
inst.insertBefore(MIR_Move.create(IA32_MOV, temp, mo.index.copy()));
} else if (indexType.isIntType()) {
inst.insertBefore(MIR_Unary.create(IA32_MOVSXDQ, temp, mo.index.copy()));
} else if (indexType.isByteType()) {
inst.insertBefore(MIR_Unary.create(IA32_MOVSXQ__B, temp, mo.index.copy()));
} else if (indexType.isShortType() || indexType.isCharType()) {
inst.insertBefore(MIR_Unary.create(IA32_MOVSXQ__W, temp, mo.index.copy()));
} else {
String msg = "Unhandled type: " + indexType;
if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED, msg);
}
inst.insertBefore(MIR_BinaryAcc.create(IA32_SHL, temp.copy(), IC(mo.scale)));
inst.insertBefore(MIR_BinaryAcc.create(IA32_ADD, effectiveAddress.copy(), temp.copy()));
} else {
TypeReference indexType = mo.index.getType();
if (indexType.isLongType() || indexType.isWordLikeType()) {
inst.insertBefore(MIR_BinaryAcc.create(IA32_ADD, effectiveAddress.copy(), mo.index.copy()));
} else {
temp = ir.regpool.makeTempLong();
if (indexType.isIntType()) {
inst.insertBefore(MIR_Unary.create(IA32_MOVSXDQ, temp, mo.index.copy()));
} else if (indexType.isByteType()) {
inst.insertBefore(MIR_Unary.create(IA32_MOVSXQ__B, temp, mo.index.copy()));
} else if (indexType.isShortType() || indexType.isCharType()) {
inst.insertBefore(MIR_Unary.create(IA32_MOVSXQ__W, temp, mo.index.copy()));
} else {
String msg = "Unhandled type: " + indexType;
if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED, msg);
}
inst.insertBefore(MIR_BinaryAcc.create(IA32_ADD, effectiveAddress.copy(), temp.copy()));
}
}
}
if (mo.base != null) {
inst.insertBefore(MIR_BinaryAcc.create(IA32_ADD, effectiveAddress.copy(), mo.base.copy()));
}
MemoryOperand newMo = MemoryOperand.I(effectiveAddress.copy().asRegister(), mo.size, null != mo.loc ? (LocationOperand)mo.loc.copy() : null,
mo.guard != null ? mo.guard.copy() : null);
inst.replaceOperand(mo, newMo);
}
}
}