view graal/com.oracle.max.asmdis/src/com/sun/max/asm/gen/cisc/x86/X86TemplateAssembler.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
line wrap: on
line source

/*
 * Copyright (c) 2007, 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.sun.max.asm.gen.cisc.x86;

import static com.sun.max.asm.gen.cisc.x86.X86AssemblerGenerator.*;

import java.io.*;
import java.util.*;

import com.sun.max.asm.*;
import com.sun.max.asm.amd64.*;
import com.sun.max.lang.*;
import com.sun.max.program.*;

/**
 * An assembler that creates binary instructions from templates and arguments.
 */
public class X86TemplateAssembler {

    private static final int MORE_BYTES_THAN_ANY_INSTRUCTION = 32;
    private final byte[] bytes = new byte[MORE_BYTES_THAN_ANY_INSTRUCTION];
    private int n;

    private void emit(byte b) {
        bytes[n++] = b;
    }

    private void emit(int b) {
        bytes[n++] = (byte) (b & 0xff);
    }

    private void emit(HexByte b) {
        bytes[n++] = b.byteValue();
    }

    private int createRexData(int bitIndex, Argument argument, boolean unconditionalRexBit) {
        if (unconditionalRexBit) {
            return ((int) argument.asLong() & 8) >> (3 - bitIndex);
        }
        int result = 0;
        if (argument instanceof AMD64GeneralRegister8) {
            final AMD64GeneralRegister8 reg8 = (AMD64GeneralRegister8) argument;
            if (reg8.requiresRexPrefix()) {
                result |= basicRexValue(template);
                if (argument.asLong() >= 8) {
                    result |= createRexData(bitIndex, argument.asLong());
                }
            }
        } else {
            if (argument.asLong() >= 8) {
                result |= createRexData(bitIndex, argument.asLong()) + basicRexValue(template);
            }
        }
        return result;
    }

    private static int createRexData(int bitIndex, long argument) {
        final byte b = (byte) (argument & 0xffL);
        if (b == 0) {
            return 0;
        }
        return X86Field.inRexPlace(bitIndex, b);
    }

    private static int createFieldData(X86Field field, long argument) {
        return field.inPlace((byte) (argument & field.mask));
    }

    private final X86Template template;
    private WordWidth addressWidth;

    public X86TemplateAssembler(X86Template template, WordWidth addressWidth) {
        this.template = template;
        this.addressWidth = addressWidth;
    }

    private int createModRMByte() {
        if (!template.hasModRMByte()) {
            return 0;
        }
        int result = template.modCase().ordinal() << X86Field.MOD.shift();
        if (template.modRMGroupOpcode() != null) {
            result |= template.modRMGroupOpcode().byteValue() << X86Field.REG.shift();
        }
        result |= template.rmCase().value() << X86Field.RM.shift();
        return result;
    }

    private int createSibByte() {
        if (template.hasSibByte() && template.sibBaseCase() == X86TemplateContext.SibBaseCase.SPECIAL) {
            return 5 << X86Field.BASE.shift();
        }
        return 0;
    }

    private static boolean modRMRequiresSib(int modRMByte) {
        final byte m = (byte) modRMByte;
        return X86Field.MOD.extract(m) != 3 && X86Field.RM.extract(m) == 4;
    }

    private static boolean modRMRequiresImmediate(int modRMByte) {
        final byte m = (byte) modRMByte;
        return X86Field.MOD.extract(m) == 0 && X86Field.RM.extract(m) == 5;
    }

    private static boolean sibRequiresImmediate(int sibRMByte) {
        final byte s = (byte) sibRMByte;
        return X86Field.BASE.extract(s) == 5;
    }

    public byte[] assemble(List<Argument> arguments) {
        int curRexByte = 0;
        final boolean unconditionalRexBit = template.operandSizeAttribute() == WordWidth.BITS_64 && template.instructionDescription().defaultOperandSize() != WordWidth.BITS_64;
        if (unconditionalRexBit) {
            curRexByte = X86Opcode.REX_MIN.byteValue() | (1 << X86Field.REX_W_BIT_INDEX);
        }
        int opcode1 = template.opcode1().byteValue() & 0xff;
        int opcode2 = template.opcode2() == null ? 0 : template.opcode2().byteValue() & 0xff;
        int modRMByte = createModRMByte();
        int sibByte = createSibByte();
        final ByteArrayOutputStream appendStream = new ByteArrayOutputStream();
        for (int i = 0; i < arguments.size(); i++) {
            final X86Parameter parameter = template.parameters().get(i);
            final long argument = arguments.get(i).asLong();
            switch (parameter.place()) {
                case MOD_REG_REXR:
                    curRexByte |= createRexData(X86Field.REX_R_BIT_INDEX, arguments.get(i), unconditionalRexBit);
                    // fall through...
                case MOD_REG:
                    modRMByte |= createFieldData(X86Field.REG, argument);
                    break;
                case MOD_RM_REXB:
                    curRexByte |= createRexData(X86Field.REX_B_BIT_INDEX, arguments.get(i), unconditionalRexBit);
                    // fall through...
                case MOD_RM:
                    modRMByte |= createFieldData(X86Field.RM, argument);
                    break;
                case SIB_BASE_REXB:
                    curRexByte |= createRexData(X86Field.REX_B_BIT_INDEX, arguments.get(i), unconditionalRexBit);
                    // fall through...
                case SIB_BASE:
                    sibByte |= createFieldData(X86Field.BASE, argument);
                    break;
                case SIB_INDEX_REXX:
                    curRexByte |= createRexData(X86Field.REX_X_BIT_INDEX, arguments.get(i), unconditionalRexBit);
                    // fall through...
                case SIB_INDEX:
                    sibByte |= createFieldData(X86Field.INDEX, argument);
                    break;
                case SIB_SCALE:
                    sibByte |= createFieldData(X86Field.SCALE, argument);
                    break;
                case APPEND:
                    if (parameter instanceof X86EnumerableParameter) {
                        appendStream.write((byte) (argument & 0xffL));
                    } else {
                        try {
                            final X86NumericalParameter numericalParameter = (X86NumericalParameter) parameter;
                            switch (numericalParameter.width()) {
                                case BITS_8:
                                    appendStream.write((byte) (argument & 0xffL));
                                    break;
                                case BITS_16:
                                    Endianness.LITTLE.writeShort(appendStream, (short) (argument & 0xffffL));
                                    break;
                                case BITS_32:
                                    Endianness.LITTLE.writeInt(appendStream, (int) (argument & 0xffffffffL));
                                    break;
                                case BITS_64:
                                    Endianness.LITTLE.writeLong(appendStream, argument);
                                    break;
                            }
                        } catch (IOException ioException) {
                            throw ProgramError.unexpected();
                        }
                    }
                    break;
                case OPCODE1_REXB:
                    curRexByte |= createRexData(X86Field.REX_B_BIT_INDEX, arguments.get(i), unconditionalRexBit);
                    // fall through...
                case OPCODE1:
                    opcode1 |= (int) argument & 7;
                    break;
                case OPCODE2_REXB:
                    curRexByte |= createRexData(X86Field.REX_B_BIT_INDEX, arguments.get(i), unconditionalRexBit);
                    // fall through...
                case OPCODE2:
                    opcode2 |= (int) argument & 7;
                    break;
            }
        }
        if (curRexByte > 0) {
            emit(curRexByte);
        }
        if (template.addressSizeAttribute() != addressWidth) {
            emit(X86Opcode.ADDRESS_SIZE);
        }
        if (template.operandSizeAttribute() == WordWidth.BITS_16) {
            emit(X86Opcode.OPERAND_SIZE);
        }
        if (template.instructionSelectionPrefix() != null) {
            emit(template.instructionSelectionPrefix());
        }
        emit(opcode1);
        if (opcode2 != 0) {
            emit(opcode2);
        }
        if (template.hasModRMByte()) {
            emit(modRMByte);
            if (modRMRequiresImmediate(modRMByte) && appendStream.size() == 0) {
                return null;
            }
        }
        if (template.hasSibByte()) {
            if (sibRequiresImmediate(sibByte) && appendStream.size() == 0) {
                return null;
            }
            emit(sibByte);
        } else if (modRMRequiresSib(modRMByte)) {
            return null;
        }
        for (byte b : appendStream.toByteArray()) {
            emit(b);
        }
        return Bytes.withLength(bytes, n);
    }

}