view graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRInstruction.java @ 4142:bc8527f3071c

Adjust code base to new level of warnings.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sun, 18 Dec 2011 05:24:06 +0100
parents e233f5660da4
children f5328dda9714
line wrap: on
line source

/*
 * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.oracle.max.graal.compiler.lir;

import com.oracle.max.graal.compiler.asm.*;
import com.oracle.max.graal.compiler.lir.LIRDebugInfo.ValueProcedure;
import com.oracle.max.graal.compiler.util.*;
import com.sun.cri.ci.*;
import com.sun.cri.ci.CiValue.Formatter;

/**
 * The {@code LIRInstruction} class definition.
 */
public abstract class LIRInstruction {

    public static final CiValue[] NO_OPERANDS = {};

    public static final OperandMode[] OPERAND_MODES = OperandMode.values();

    /**
     * Constants denoting how a LIR instruction uses an operand.
     */
    public enum OperandMode {
        /**
         * The value must have been defined before. It is alive before the instruction until the beginning of the
         * instruction, but not necessarily throughout the instruction. A register assigned to it can also be assigend
         * to a Temp or Output operand. The value can be used again after the instruction, so the instruction must not
         * modify the register.
         */
        Input,

        /**
         * The value must have been defined before. It is alive before the instruction and throughout the instruction. A
         * register assigned to it cannot be assigned to a Temp or Output operand. The value can be used again after the
         * instruction, so the instruction must not modify the register.
         */
        Alive,

        /**
         * The value must not have been defined before, and must not be used after the instruction. The instruction can
         * do whatever it wants with the register assigned to it (or not use it at all).
         */
        Temp,

        /**
         * The value must not have been defined beforee. The instruction has to assign a value to the register. The
         * value can (and most likely will) be used after the instruction.
         */
        Output,
    }

    /**
     * The opcode of this instruction.
     */
    public final LIROpcode code;

    /**
     * The result operand for this instruction (modified by the register allocator).
     */
    protected CiValue result;

    /**
     * The input operands for this instruction (modified by the register allocator).
     */
    protected final CiValue[] inputs;

    /**
     * The alive operands for this instruction (modified by the register allocator).
     */
    protected final CiValue[] alives;

    /**
     * The temp operands for this instruction (modified by the register allocator).
     */
    protected final CiValue[] temps;

    /**
     * Used to emit debug information.
     */
    public final LIRDebugInfo info;

    /**
     * Instruction id for register allocation.
     */
    private int id;

    /**
     * Constructs a new LIR instruction that has input and temp operands.
     *
     * @param opcode the opcode of the new instruction
     * @param result the operand that holds the operation result of this instruction. This will be
     *            {@link CiValue#IllegalValue} for instructions that do not produce a result.
     * @param info the {@link LIRDebugInfo} info that is to be preserved for the instruction. This will be {@code null} when no debug info is required for the instruction.
     * @param inputs the input operands for the instruction.
     * @param temps the temp operands for the instruction.
     */
    public LIRInstruction(LIROpcode opcode, CiValue result, LIRDebugInfo info, CiValue[] inputs, CiValue[] alives, CiValue[] temps) {
        this.code = opcode;
        this.result = result;
        this.inputs = inputs;
        this.alives = alives;
        this.temps = temps;
        this.info = info;
        this.id = -1;
    }

    public abstract void emitCode(TargetMethodAssembler tasm);


    public final int id() {
        return id;
    }

    public final void setId(int id) {
        this.id = id;
    }

    /**
     * Gets an input operand of this instruction.
     *
     * @param index the index of the operand requested.
     * @return the {@code index}'th input operand.
     */
    public final CiValue input(int index) {
        return inputs[index];
    }

    /**
     * Gets an alive operand of this instruction.
     *
     * @param index the index of the operand requested.
     * @return the {@code index}'th alive operand.
     */
    public final CiValue alive(int index) {
        return alives[index];
    }

    /**
     * Gets a temp operand of this instruction.
     *
     * @param index the index of the operand requested.
     * @return the {@code index}'th temp operand.
     */
    public final CiValue temp(int index) {
        return temps[index];
    }

    /**
     * Gets the result operand for this instruction.
     *
     * @return return the result operand
     */
    public final CiValue result() {
        return result;
    }

    /**
     * Gets the instruction name.
     */
    public String name() {
        return code.toString();
    }

    public boolean hasOperands() {
        return inputs.length > 0 || alives.length > 0 || temps.length > 0 || info != null || hasCall();
    }

    public final int operandCount(OperandMode mode) {
        switch (mode) {
            case Output: return result.isLegal() ? 1 : 0;
            case Input:  return inputs.length;
            case Alive:  return alives.length;
            case Temp:   return temps.length;
            default:     throw Util.shouldNotReachHere();
        }
    }

    public final CiValue operandAt(OperandMode mode, int index) {
        assert index < operandCount(mode);
        switch (mode) {
            case Output: return result;
            case Input:  return inputs[index];
            case Alive:  return alives[index];
            case Temp:   return temps[index];
            default:     throw Util.shouldNotReachHere();
        }
    }

    public final void setOperandAt(OperandMode mode, int index, CiValue location) {
        assert index < operandCount(mode);
        assert location.kind != CiKind.Illegal;
        assert operandAt(mode, index).isVariable() && operandAt(mode, index).kind == location.kind;
        switch (mode) {
            case Output: result = location; break;
            case Input:  inputs[index] = location; break;
            case Alive:  alives[index] = location; break;
            case Temp:   temps[index] = location; break;
            default:     throw Util.shouldNotReachHere();
        }
    }

    public final void forEachOperand(OperandMode mode, ValueProcedure proc) {
        for (int i = 0; i < operandCount(mode); i++) {
            CiValue newValue = proc.doValue(operandAt(mode, i));
            if (newValue != null) {
                setOperandAt(mode, i, newValue);
            }
        }
    }

    /**
     * Returns true when this instruction is a call instruction that destroys all caller-saved registers.
     */
    public boolean hasCall() {
        return false;
    }

    /**
     * Used by the register allocator.  The result operand of this instruction should get
     * the same register assigned as the returned operand.
     * @return The register hint for the output operand, or null if no register hint should be defined.
     */
    public CiValue registerHint() {
        return null;
    }

    /**
     * Used by the register allocator to decide whether an input operand can be assigned a stack slot.
     * Subclasses should override this method when an input can be memory.
     * @param index The index of the operand in {@link #inputs}.
     * @return true if the input operand with the given index can be assigned a stack slot.
     */
    public boolean inputCanBeMemory(int index) {
        return false;
    }


    @Override
    public String toString() {
        return toString(Formatter.DEFAULT);
    }

    public final String toStringWithIdPrefix() {
        if (id != -1) {
            return String.format("%4d %s", id, toString());
        }
        return "     " + toString();
    }

    /**
     * Gets the operation performed by this instruction in terms of its operands as a string.
     */
    public String operationString(Formatter operandFmt) {
        StringBuilder buf = new StringBuilder();
        if (result.isLegal()) {
            buf.append(operandFmt.format(result)).append(" = ");
        }
        if (inputs.length + alives.length > 1) {
            buf.append("(");
        }
        String sep = "";
        for (CiValue input : inputs) {
            buf.append(sep).append(operandFmt.format(input));
            sep = ", ";
        }
        for (CiValue input : alives) {
            buf.append(sep).append(operandFmt.format(input)).append(" ~");
            sep = ", ";
        }
        if (inputs.length + alives.length > 1) {
            buf.append(")");
        }

        if (temps.length > 0) {
            buf.append(" [");
        }
        sep = "";
        for (CiValue temp : temps) {
            buf.append(sep).append(operandFmt.format(temp));
            sep = ", ";
        }
        if (temps.length > 0) {
            buf.append("]");
        }
        return buf.toString();
    }

    protected static String refMapToString(CiDebugInfo debugInfo, Formatter operandFmt) {
        StringBuilder buf = new StringBuilder();
        if (debugInfo.hasStackRefMap()) {
            CiBitMap bm = debugInfo.frameRefMap;
            for (int slot = bm.nextSetBit(0); slot >= 0; slot = bm.nextSetBit(slot + 1)) {
                if (buf.length() != 0) {
                    buf.append(", ");
                }
                buf.append(operandFmt.format(CiStackSlot.get(CiKind.Object, slot)));
            }
        }
        if (debugInfo.hasRegisterRefMap()) {
            CiBitMap bm = debugInfo.registerRefMap;
            for (int reg = bm.nextSetBit(0); reg >= 0; reg = bm.nextSetBit(reg + 1)) {
                if (buf.length() != 0) {
                    buf.append(", ");
                }
                buf.append("r").append(reg);
            }
        }
        return buf.toString();
    }

    protected void appendDebugInfo(StringBuilder buf, Formatter operandFmt) {
        if (info != null) {
            buf.append(" [bci:").append(info.topFrame.bci);
            if (info.hasDebugInfo()) {
                CiDebugInfo debugInfo = info.debugInfo();
                String refmap = refMapToString(debugInfo, operandFmt);
                if (refmap.length() != 0) {
                    buf.append(", refmap(").append(refmap.trim()).append(')');
                }
            }
            buf.append(']');
        }
    }

    public String toString(Formatter operandFmt) {
        StringBuilder buf = new StringBuilder(name()).append(' ').append(operationString(operandFmt));
        appendDebugInfo(buf, operandFmt);
        return buf.toString();
    }
}