/* * 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.ir; import org.jikesrvm.compilers.opt.OPT_OptimizingCompilerException; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.Offset; /** * A memory operand. * Used to represent complex addrssing modes on CISC machines. * A memory operand contains some set of other operands that are used * in the address calculation. * * May contain 0, 1, or 2 OPT_RegisterOperands as well as a scale factor and * dispacement. * * The effective address represented by this operand is: * [base] + [index]*(2^scale) + disp * * @see OPT_Operand */ public final class OPT_MemoryOperand extends OPT_Operand { /** * The location operand describing this memory access */ public OPT_LocationOperand loc; /** * The guard operand that validates this memory access */ public OPT_Operand guard; /** * The base register (may be null) */ public OPT_RegisterOperand base; /** * The index register (may be null) */ public OPT_RegisterOperand index; /** * The scale value (log power of 2) * valid values are 0,1,2,3 */ public byte scale; /** * The displacement */ public Offset disp; /** * Number of bytes being accessed (1,2,4,8) */ public byte size; public OPT_MemoryOperand(OPT_RegisterOperand base, OPT_RegisterOperand index, byte scale, Offset disp, byte size, OPT_LocationOperand loc, OPT_Operand guard) { this.loc = loc; this.guard = guard; this.base = base; this.index = index; this.scale = scale; this.disp = disp; this.size = size; if (loc != null) loc.instruction = null; if (guard != null) guard.instruction = null; if (base != null) base.instruction = null; if (index != null) index.instruction = null; } // Shortcuts for some common addressing modes public static OPT_MemoryOperand B(OPT_RegisterOperand base, byte size, OPT_LocationOperand loc, OPT_Operand guard) { return new OPT_MemoryOperand(base, null, (byte) 0, Offset.zero(), size, loc, guard); } public static OPT_MemoryOperand BI(OPT_RegisterOperand base, OPT_RegisterOperand index, byte size, OPT_LocationOperand loc, OPT_Operand guard) { return new OPT_MemoryOperand(base, index, (byte) 0, Offset.zero(), size, loc, guard); } public static OPT_MemoryOperand BD(OPT_RegisterOperand base, Offset disp, byte size, OPT_LocationOperand loc, OPT_Operand guard) { return new OPT_MemoryOperand(base, null, (byte) 0, disp, size, loc, guard); } public static OPT_MemoryOperand BID(OPT_RegisterOperand base, OPT_RegisterOperand index, Offset disp, byte size, OPT_LocationOperand loc, OPT_Operand guard) { return new OPT_MemoryOperand(base, index, (byte) 0, disp, size, loc, guard); } public static OPT_MemoryOperand BIS(OPT_RegisterOperand base, OPT_RegisterOperand index, byte scale, byte size, OPT_LocationOperand loc, OPT_Operand guard) { return new OPT_MemoryOperand(base, index, scale, Offset.zero(), size, loc, guard); } public static OPT_MemoryOperand D(Address disp, byte size, OPT_LocationOperand loc, OPT_Operand guard) { return new OPT_MemoryOperand(null, null, (byte) 0, disp.toWord().toOffset(), size, loc, guard); } public static OPT_MemoryOperand I(OPT_RegisterOperand base, byte size, OPT_LocationOperand loc, OPT_Operand guard) { return new OPT_MemoryOperand(base, null, (byte) 0, Offset.zero(), size, loc, guard); } /** * Returns a copy of the current operand. */ public OPT_Operand copy() { OPT_RegisterOperand newBase = (base != null) ? (OPT_RegisterOperand) base.copy() : null; OPT_RegisterOperand newIndex = (index != null) ? (OPT_RegisterOperand) index.copy() : null; OPT_LocationOperand newLoc = (loc != null) ? (OPT_LocationOperand) loc.copy() : null; OPT_Operand newGuard = (guard != null) ? guard.copy() : null; return new OPT_MemoryOperand(newBase, newIndex, scale, disp, size, newLoc, newGuard); } /** * Returns if this operand is the 'same' as another operand. * * @param op other operand */ public boolean similar(OPT_Operand op) { if (op instanceof OPT_MemoryOperand) { OPT_MemoryOperand mop = (OPT_MemoryOperand) op; if (base == null) { if (mop.base != null) return false; } else { if (mop.base == null) return false; if (!base.similar(mop.base)) return false; } if (index == null) { if (mop.index != null) return false; } else { if (mop.index == null) return false; if (!index.similar(mop.index)) return false; } return (mop.scale == scale) && (mop.disp.EQ(disp)) && (mop.size == size); } else { return false; } } /** * Return a string rep of the operand (ie the effective address) */ public String toString() { String addr = (base == null) ? "<0" : "<[" + base + "]"; if (index != null) { addr += "+[" + index; switch (scale) { case 0: addr += "]"; break; case 1: addr += "*2]"; break; case 2: addr += "*4]"; break; case 3: addr += "*8]"; break; default: OPT_OptimizingCompilerException.UNREACHABLE(); } } if (!disp.isZero()) { addr += "+" + disp.toInt(); } switch (size) { case 1: addr += ">B"; break; case 2: addr += ">W"; break; case 4: addr += ">DW"; break; case 8: addr += ">QW"; break; default: OPT_OptimizingCompilerException.UNREACHABLE(); } if (loc != null && guard != null) { addr += " (" + loc + ", " + guard + ")"; } else if (loc != null) { addr += " (" + loc + ")"; } else if (guard != null) { addr += " (" + guard + ")"; } return addr; } }