/* * 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; import org.jikesrvm.VM; import org.jikesrvm.compilers.opt.ir.ALoad; import org.jikesrvm.compilers.opt.ir.AStore; import org.jikesrvm.compilers.opt.ir.Binary; import org.jikesrvm.compilers.opt.ir.Load; import org.jikesrvm.compilers.opt.ir.OPT_DoubleConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_FloatConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_Instruction; import org.jikesrvm.compilers.opt.ir.OPT_IntConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_LocationOperand; import org.jikesrvm.compilers.opt.ir.OPT_MemoryOperand; import org.jikesrvm.compilers.opt.ir.OPT_Operand; import org.jikesrvm.compilers.opt.ir.OPT_RegisterOperand; import org.jikesrvm.compilers.opt.ir.Store; import org.vmmagic.unboxed.Offset; /** * Contains common BURS helper functions for platforms with memory operands. */ public abstract class OPT_BURS_MemOp_Helpers extends OPT_BURS_Common_Helpers { // word size for memory operands protected static final byte B = 0x01; // byte (8 bits) protected static final byte W = 0x02; // word (16 bits) protected static final byte DW = 0x04; // doubleword (32 bits) protected static final byte QW = 0x08; // quadword (64 bits) protected static final byte B_S = 0x00; // byte (8*2^0 bits) protected static final byte W_S = 0x01; // word (8*2^116 bits) protected static final byte DW_S = 0x02; // doubleword (8*2^2 bits) protected static final byte QW_S = 0x03; // quadword (8*2^3 bits) protected OPT_BURS_MemOp_Helpers(OPT_BURS burs) { super(burs); } // Cost functions better suited to grammars with multiple non-termials protected final int ADDRESS_EQUAL(OPT_Instruction store, OPT_Instruction load, int trueCost) { return ADDRESS_EQUAL(store, load, trueCost, INFINITE); } protected final int ADDRESS_EQUAL(OPT_Instruction store, OPT_Instruction load, int trueCost, int falseCost) { if (Store.getAddress(store).similar(Load.getAddress(load)) && Store.getOffset(store).similar(Load.getOffset(load))) { return trueCost; } else { return falseCost; } } protected final int ARRAY_ADDRESS_EQUAL(OPT_Instruction store, OPT_Instruction load, int trueCost) { return ARRAY_ADDRESS_EQUAL(store, load, trueCost, INFINITE); } protected final int ARRAY_ADDRESS_EQUAL(OPT_Instruction store, OPT_Instruction load, int trueCost, int falseCost) { if (AStore.getArray(store).similar(ALoad.getArray(load)) && AStore.getIndex(store).similar(ALoad.getIndex(load))) { return trueCost; } else { return falseCost; } } // support to remember an address being computed in a subtree private static final class AddrStackElement { OPT_RegisterOperand base; OPT_RegisterOperand index; byte scale; Offset displacement; AddrStackElement next; AddrStackElement(OPT_RegisterOperand b, OPT_RegisterOperand i, byte s, Offset d, AddrStackElement n) { base = b; index = i; scale = s; displacement = d; next = n; } } private AddrStackElement AddrStack; protected final void pushAddress(OPT_RegisterOperand base, OPT_RegisterOperand index, byte scale, Offset disp) { AddrStack = new AddrStackElement(base, index, scale, disp, AddrStack); } protected final void augmentAddress(OPT_Operand op) { if (VM.VerifyAssertions) VM._assert(AddrStack != null, "No address to augment"); if (op.isRegister()) { OPT_RegisterOperand rop = op.asRegister(); if (AddrStack.base == null) { AddrStack.base = rop; } else if (AddrStack.index == null) { if (VM.VerifyAssertions) VM._assert(AddrStack.scale == (byte) 0); AddrStack.index = rop; } else { throw new OPT_OptimizingCompilerException("three base registers in address"); } } else { int disp = ((OPT_IntConstantOperand) op).value; AddrStack.displacement = AddrStack.displacement.plus(disp); } } protected final void combineAddresses() { if (VM.VerifyAssertions) VM._assert(AddrStack != null, "No address to combine"); AddrStackElement tmp = AddrStack; AddrStack = AddrStack.next; if (VM.VerifyAssertions) VM._assert(AddrStack != null, "only 1 address to combine"); if (tmp.base != null) { if (AddrStack.base == null) { AddrStack.base = tmp.base; } else if (AddrStack.index == null) { if (VM.VerifyAssertions) VM._assert(AddrStack.scale == (byte) 0); AddrStack.index = tmp.base; } else { throw new OPT_OptimizingCompilerException("three base registers in address"); } } if (tmp.index != null) { if (AddrStack.index == null) { if (VM.VerifyAssertions) VM._assert(AddrStack.scale == (byte) 0); AddrStack.index = tmp.index; AddrStack.scale = tmp.scale; } else if (AddrStack.base == null && tmp.scale == (byte) 0) { AddrStack.base = tmp.base; } else { throw new OPT_OptimizingCompilerException("two scaled registers in address"); } } AddrStack.displacement = AddrStack.displacement.plus(tmp.displacement.toInt()); } protected final OPT_MemoryOperand consumeAddress(byte size, OPT_LocationOperand loc, OPT_Operand guard) { if (VM.VerifyAssertions) VM._assert(AddrStack != null, "No address to consume"); OPT_MemoryOperand mo = new OPT_MemoryOperand(AddrStack.base, AddrStack.index, AddrStack.scale, AddrStack.displacement, size, loc, guard); AddrStack = AddrStack.next; return mo; } // support to remember a memory operand computed in a subtree private static final class MOStackElement { OPT_MemoryOperand mo; MOStackElement next; MOStackElement(OPT_MemoryOperand m, MOStackElement n) { mo = m; next = n; } } private MOStackElement MOStack; protected final void pushMO(OPT_MemoryOperand mo) { MOStack = new MOStackElement(mo, MOStack); } protected final OPT_MemoryOperand consumeMO() { if (VM.VerifyAssertions) VM._assert(MOStack != null, "No memory operand to consume"); OPT_MemoryOperand mo = MOStack.mo; MOStack = MOStack.next; return mo; } /** * Construct a memory operand for the effective address of the * load instruction */ protected final OPT_MemoryOperand MO_L(OPT_Instruction s, byte size) { return MO_L(s, size, 0); } /** * Construct a displaced memory operand for the effective address of the * load instruction */ protected final OPT_MemoryOperand MO_L(OPT_Instruction s, byte size, int disp) { if (VM.VerifyAssertions) VM._assert(Load.conforms(s)); return MO(Load.getAddress(s), Load.getOffset(s), size, Offset.fromIntSignExtend(disp), Load.getLocation(s), Load.getGuard(s)); } /** * Construct a memory operand for the effective address of the * store instruction */ protected final OPT_MemoryOperand MO_S(OPT_Instruction s, byte size) { return MO_S(s, size, 0); } /** * Construct a displaced memory operand for the effective address of the * store instruction */ protected final OPT_MemoryOperand MO_S(OPT_Instruction s, byte size, int disp) { if (VM.VerifyAssertions) VM._assert(Store.conforms(s)); return MO(Store.getAddress(s), Store.getOffset(s), size, Offset.fromIntSignExtend(disp), Store.getLocation(s), Store.getGuard(s)); } protected final OPT_MemoryOperand MO(OPT_Operand base, OPT_Operand offset, byte size, OPT_LocationOperand loc, OPT_Operand guard) { if (base instanceof OPT_IntConstantOperand) { if (offset instanceof OPT_IntConstantOperand) { return MO_D(Offset.fromIntSignExtend(IV(base) + IV(offset)), size, loc, guard); } else { return MO_BD(offset, Offset.fromIntSignExtend(IV(base)), size, loc, guard); } } else { if (offset instanceof OPT_IntConstantOperand) { return MO_BD(base, Offset.fromIntSignExtend(IV(offset)), size, loc, guard); } else { return MO_BI(base, offset, size, loc, guard); } } } protected final OPT_MemoryOperand MO(OPT_Operand base, OPT_Operand offset, byte size, OPT_LocationOperand loc, OPT_Operand guard, int disp) { if (base instanceof OPT_IntConstantOperand) { if (offset instanceof OPT_IntConstantOperand) { return MO_D(Offset.fromIntSignExtend(IV(base) + IV(offset) + disp), size, loc, guard); } else { return MO_BD(offset, Offset.fromIntSignExtend(IV(base)+disp), size, loc, guard); } } else { if (offset instanceof OPT_IntConstantOperand) { return MO_BD(base, Offset.fromIntSignExtend(IV(offset)+disp), size, loc, guard); } else { return MO_BID(base, offset, Offset.fromIntSignExtend(disp), size, loc, guard); } } } protected final OPT_MemoryOperand MO(OPT_Operand base, OPT_Operand offset, byte size, Offset disp, OPT_LocationOperand loc, OPT_Operand guard) { if (base instanceof OPT_IntConstantOperand) { if (offset instanceof OPT_IntConstantOperand) { return MO_D(disp.plus(IV(base) + IV(offset)), size, loc, guard); } else { return MO_BD(offset, disp.plus(IV(base)), size, loc, guard); } } else { if (offset instanceof OPT_IntConstantOperand) { return MO_BD(base, disp.plus(IV(offset)), size, loc, guard); } else { return MO_BID(base, offset, disp, size, loc, guard); } } } protected final OPT_MemoryOperand MO_B(OPT_Operand base, byte size, OPT_LocationOperand loc, OPT_Operand guard) { return OPT_MemoryOperand.B(R(base), size, loc, guard); } protected final OPT_MemoryOperand MO_BI(OPT_Operand base, OPT_Operand index, byte size, OPT_LocationOperand loc, OPT_Operand guard) { return OPT_MemoryOperand.BI(R(base), R(index), size, loc, guard); } protected final OPT_MemoryOperand MO_BD(OPT_Operand base, Offset disp, byte size, OPT_LocationOperand loc, OPT_Operand guard) { return OPT_MemoryOperand.BD(R(base), disp, size, loc, guard); } protected final OPT_MemoryOperand MO_BID(OPT_Operand base, OPT_Operand index, Offset disp, byte size, OPT_LocationOperand loc, OPT_Operand guard) { return OPT_MemoryOperand.BID(R(base), R(index), disp, size, loc, guard); } protected final OPT_MemoryOperand MO_BIS(OPT_Operand base, OPT_Operand index, byte scale, byte size, OPT_LocationOperand loc, OPT_Operand guard) { return OPT_MemoryOperand.BIS(R(base), R(index), scale, size, loc, guard); } protected final OPT_MemoryOperand MO_D(Offset disp, byte size, OPT_LocationOperand loc, OPT_Operand guard) { return OPT_MemoryOperand.D(disp.toWord().toAddress(), size, loc, guard); } /** * Construct a memory operand for the effective address of the * array load instruction */ protected final OPT_MemoryOperand MO_AL(OPT_Instruction s, byte scale, byte size) { return MO_AL(s, scale, size, 0); } /** * Construct a memory operand for the effective address of the * array load instruction */ protected final OPT_MemoryOperand MO_AL(OPT_Instruction s, byte scale, byte size, int disp) { if (VM.VerifyAssertions) VM._assert(ALoad.conforms(s)); return MO_ARRAY(ALoad.getArray(s), ALoad.getIndex(s), scale, size, Offset.fromIntSignExtend(disp), ALoad.getLocation(s), ALoad.getGuard(s)); } /** * Construct a memory operand for the effective address of the * array store instruction */ protected final OPT_MemoryOperand MO_AS(OPT_Instruction s, byte scale, byte size) { return MO_AS(s, scale, size, 0); } // Construct a memory operand for the effective address of the array store instruction protected final OPT_MemoryOperand MO_AS(OPT_Instruction s, byte scale, byte size, int disp) { if (VM.VerifyAssertions) VM._assert(AStore.conforms(s)); return MO_ARRAY(AStore.getArray(s), AStore.getIndex(s), scale, size, Offset.fromIntSignExtend(disp), AStore.getLocation(s), AStore.getGuard(s)); } /** * Construct memory operand for an array access */ private OPT_MemoryOperand MO_ARRAY(OPT_Operand base, OPT_Operand index, byte scale, byte size, Offset disp, OPT_LocationOperand loc, OPT_Operand guard) { if (base instanceof OPT_IntConstantOperand) { if (index instanceof OPT_IntConstantOperand) { return MO_D(disp.plus(IV(base) + (IV(index) << scale)), size, loc, guard); } else { return new OPT_MemoryOperand(null, R(index), scale, disp.plus(IV(base)), size, loc, guard); } } else { if (index instanceof OPT_IntConstantOperand) { return MO_BD(base, disp.plus(IV(index) << scale), size, loc, guard); } else { return new OPT_MemoryOperand(R(base), R(index), scale, disp, size, loc, guard); } } } /** * Construct memory operand for a MATERIALIZE_FP_CONSTANT */ protected final OPT_MemoryOperand MO_MC(OPT_Instruction s) { OPT_Operand base = Binary.getVal1(s); // JTOC OPT_Operand val = Binary.getVal2(s); // float or double value if (val instanceof OPT_FloatConstantOperand) { OPT_FloatConstantOperand fc = (OPT_FloatConstantOperand) val; Offset offset = fc.offset; OPT_LocationOperand loc = new OPT_LocationOperand(offset); if (base instanceof OPT_IntConstantOperand) { return MO_D(offset.plus(IV(base)), DW, loc, TG()); } else { return MO_BD(base, offset, DW, loc, TG()); } } else { OPT_DoubleConstantOperand dc = (OPT_DoubleConstantOperand) val; Offset offset = dc.offset; OPT_LocationOperand loc = new OPT_LocationOperand(offset); if (base instanceof OPT_IntConstantOperand) { return MO_D(offset.plus(IV(base)), QW, loc, TG()); } else { return MO_BD(Binary.getVal1(s), dc.offset, QW, loc, TG()); } } } }