view graal/com.oracle.max.asmdis/src/com/sun/max/asm/gen/cisc/x86/X86AssemblerGenerator.java @ 3733:e233f5660da4

Added Java files from Maxine project.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sat, 17 Dec 2011 19:59:18 +0100
parents
children bc8527f3071c
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 java.io.*;
import java.util.*;

import com.sun.max.*;
import com.sun.max.asm.*;
import com.sun.max.asm.gen.*;
import com.sun.max.io.*;
import com.sun.max.lang.*;
import com.sun.max.program.*;
import com.sun.max.program.option.*;

/**
 */
public abstract class X86AssemblerGenerator<Template_Type extends X86Template> extends AssemblerGenerator<Template_Type> {

    private final Option<Boolean> support16BitAddressesOption = options.newBooleanOption("a16", false, "Enables 16 bit addressing.");
    private final Option<Boolean> support16BitOffsetOption = options.newBooleanOption("d16", false, "Enables 16 bit offsets.");

    private final WordWidth addressWidth;

    protected X86AssemblerGenerator(Assembly<Template_Type> assembly, WordWidth addressWidth) {
        super(assembly, true);
        this.addressWidth = addressWidth;
    }

    @Override
    public X86Assembly<Template_Type> assembly() {
        final Class<X86Assembly<Template_Type>> type = null;
        return Utils.cast(type, super.assembly());
    }

    public WordWidth addressWidth() {
        return addressWidth;
    }

    @Override
    protected void generate() {
        if (support16BitAddressesOption.getValue() != null && support16BitAddressesOption.getValue()) {
            X86Assembly.support16BitAddresses();
        }
        if (support16BitOffsetOption.getValue() != null && support16BitOffsetOption.getValue()) {
            X86Assembly.support16BitOffsets();
        }
        super.generate();
    }

    protected X86Parameter getParameter(Template_Type template, Class parameterType) {
        for (X86Parameter parameter : template.parameters()) {
            if (parameter.type() == parameterType) {
                return parameter;
            }
        }
        throw ProgramError.unexpected("found no parameter of type: " + parameterType);
    }

    private void printCallWithByteDisplacement(IndentWriter writer, Template_Type template, Class argumentType) {
        final Template_Type modVariantTemplate = X86Assembly.getModVariantTemplate(assembly().templates(), template, argumentType);
        final String subroutineName = makeSubroutine(modVariantTemplate);
        writer.print(subroutineName + "(");
        if (template.opcode2() != null) {
            writer.print(OPCODE2_VARIABLE_NAME);
        } else {
            writer.print(OPCODE1_VARIABLE_NAME);
        }
        if (template.modRMGroupOpcode() != null) {
            writer.print(", " + MODRM_GROUP_OPCODE_VARIABLE_NAME);
        }
        for (X86Parameter parameter : template.parameters()) {
            if (parameter.type() == argumentType) {
                writer.print(", (byte) 0");
            }
            writer.print(", " + parameter.variableName());
        }
        writer.println(");");
    }

    protected String asIdentifier(EnumerableArgument argument) {
        return argument.getClass().getSimpleName() + "." + argument.name();
    }

    protected <Argument_Type extends Enum<Argument_Type> & EnumerableArgument<Argument_Type>> void printModVariant(IndentWriter writer, final Template_Type template, Argument_Type... arguments) {
        final Class argumentType = arguments[0].getClass();
        final X86Parameter parameter = getParameter(template, argumentType);
        writer.print("if (");
        String separator = "";
        for (EnumerableArgument argument : arguments) {
            writer.print(separator + parameter.variableName() + " == " + asIdentifier(argument));
            separator = " || ";
        }
        writer.println(") {");
        writer.indent();
        printCallWithByteDisplacement(writer, template, argumentType);
        writer.println("return;");
        writer.outdent();
        writer.println("}");
    }

    protected abstract void printModVariants(IndentWriter writer, Template_Type template);

    protected void printPrefixes(IndentWriter writer, Template_Type template) {
        if (template.addressSizeAttribute() != addressWidth()) {
            emitByte(writer, X86Opcode.ADDRESS_SIZE.byteValue());
            writer.println(" // address size prefix");
        }
        if (template.operandSizeAttribute() == WordWidth.BITS_16) {
            emitByte(writer, X86Opcode.OPERAND_SIZE.byteValue());
            writer.println(" // operand size prefix");
        }
        if (template.instructionSelectionPrefix() != null) {
            emitByte(writer, template.instructionSelectionPrefix().byteValue());
            writer.println(" // instruction selection prefix");
        }
    }

    private void printOpcode(IndentWriter writer, Template_Type template, String opcodeVarName, final ParameterPlace parameterPlace32, ParameterPlace parameterPlace64) {
        String comment = "";
        String opcodeVariableName = opcodeVarName;
        for (X86Parameter parameter : template.parameters()) {
            if (parameter.place() == parameterPlace32) {
                opcodeVariableName += " + " + parameter.valueString();
                comment = " // " + parameterPlace32.name().toLowerCase();
            } else if (parameter.place() == parameterPlace64) {
                opcodeVariableName += " + (" + parameter.valueString() + "& 7)";
                comment = " // " + parameterPlace64.name().toLowerCase();
            }
        }
        if (comment.length() == 0) {
            emitByte(writer, opcodeVariableName);
            writer.println();
        } else {
            emitByte(writer, "(byte) (" + opcodeVariableName + ")");
            writer.println(comment);
        }
    }

    private static final String MODRM_BYTE_VARIABLE_NAME = "modRMByte";

    private void printModRMByte(IndentWriter writer, Template_Type template) {
        writer.print("byte " + MODRM_BYTE_VARIABLE_NAME + " = (byte) ((" + template.modCase().ordinal() + " << " + X86Field.MOD.shift() + ")");
        if (template.modRMGroupOpcode() != null) {
            writer.print(" | (" + MODRM_GROUP_OPCODE_VARIABLE_NAME + " << " + X86Field.REG.shift() + ")");
        }
        writer.print("); // mod field");
        if (template.modRMGroupOpcode() != null) {
            writer.print(", group opcode in reg field");
        }
        writer.println();
        switch (template.rmCase()) {
            case SIB:
            case SWORD:
            case SDWORD: {
                writer.println(MODRM_BYTE_VARIABLE_NAME + " |= " + template.rmCase().value() + " << " + X86Field.RM.shift() + "; // rm field");
                break;
            }
            default:
                break;
        }
        for (X86Parameter parameter : template.parameters()) {
            switch (parameter.place()) {
                case MOD_REG:
                case MOD_REG_REXR: {
                    writer.println(MODRM_BYTE_VARIABLE_NAME + " |= (" + parameter.valueString() + " & 7) << " + X86Field.REG.shift() + "; // reg field");
                    break;
                }
                case MOD_RM:
                case MOD_RM_REXB: {
                    writer.println(MODRM_BYTE_VARIABLE_NAME + " |= (" + parameter.valueString() + " & 7) << " + X86Field.RM.shift() + "; // rm field");
                    break;
                }
                default:
                    break;
            }
        }
        emitByte(writer, MODRM_BYTE_VARIABLE_NAME);
        writer.println();
    }

    private static final String SIB_BYTE_NAME = "sibByte";

    private void printSibByte(IndentWriter writer, Template_Type template) {
        writer.print("byte " + SIB_BYTE_NAME + " = ");
        if (template.sibBaseCase() == X86TemplateContext.SibBaseCase.SPECIAL) {
            writer.println("(byte) (5 << " + X86Field.BASE.shift() + "); // base field");
        } else {
            writer.println("(byte) 0;");
        }
        for (X86Parameter parameter : template.parameters()) {
            switch (parameter.place()) {
                case SIB_BASE:
                case SIB_BASE_REXB:
                    writer.println(SIB_BYTE_NAME + " |= (" + parameter.valueString() + " & 7) << " + X86Field.BASE.shift() + "; // base field");
                    break;
                case SIB_INDEX:
                case SIB_INDEX_REXX:
                    writer.println(SIB_BYTE_NAME + " |= (" + parameter.valueString() + " & 7) << " + X86Field.INDEX.shift() + "; // index field");
                    break;
                case SIB_SCALE:
                    writer.println(SIB_BYTE_NAME + " |= " + parameter.valueString() + " << " + X86Field.SCALE.shift() + "; // scale field");
                    break;
                default:
                    break;
            }
        }
        emitByte(writer, SIB_BYTE_NAME);
        writer.println();
    }

    protected <Argument_Type extends Enum<Argument_Type> & EnumerableArgument<Argument_Type>> void printSibVariant(IndentWriter writer, Template_Type template, Argument_Type... arguments) {
        final Class argumentType = arguments[0].getClass();
        final X86Parameter parameter = getParameter(template, argumentType);
        writer.print("if (");
        String separator = "";
        for (EnumerableArgument argument : arguments) {
            writer.print(separator + parameter.variableName() + " == " + asIdentifier(argument));
            separator = " || ";
        }
        writer.println(") {");
        writer.indent();
        emitByte(writer, (byte) 0x24);
        writer.println(" // SIB byte");
        writer.outdent();
        writer.println("}");
    }

    protected abstract void printSibVariants(IndentWriter writer, Template_Type template);

    private void printImmediateParameter(IndentWriter writer, X86NumericalParameter parameter) {
        if (parameter.width() == WordWidth.BITS_8) {
            emitByte(writer, parameter.variableName());
            writer.println(" // appended");
        } else {
            writer.println("// appended:");
            for (int i = 0; i < parameter.width().numberOfBytes; i++) {
                if (i > 0) {
                    writer.println(parameter.variableName() + " >>= 8;");
                }
                emitByte(writer, "(byte) (" + parameter.variableName() + " & 0xff)");
                writer.println();
            }
        }
    }

    private void printAppendedEnumerableParameter(IndentWriter writer, X86EnumerableParameter parameter) {
        emitByte(writer, "(byte) " + parameter.variableName() + ".value()");
        writer.println(" // appended");
    }

    private void printAppendedParameter(IndentWriter writer, Template_Type template) {
        for (X86Parameter parameter : template.parameters()) {
            if (parameter.place() == ParameterPlace.APPEND) {
                if (parameter instanceof X86NumericalParameter) {
                    printImmediateParameter(writer, (X86NumericalParameter) parameter);
                } else if (parameter instanceof X86EnumerableParameter) {
                    printAppendedEnumerableParameter(writer, (X86EnumerableParameter) parameter);
                } else {
                    throw ProgramError.unexpected("appended parameter of unexpected type: " + parameter);
                }
            }
        }
    }

    private int subroutineSerial;

    private String createSubroutineName() {
        ++subroutineSerial;
        String number = Integer.toString(subroutineSerial);
        while (number.length() < 4) {
            number = "0" + number;
        }
        return "assemble" + number;
    }

    private Map<String, String> subroutineToName = new HashMap<String, String>();

    private static final String OPCODE1_VARIABLE_NAME = "opcode1";
    private static final String OPCODE2_VARIABLE_NAME = "opcode2";
    private static final String MODRM_GROUP_OPCODE_VARIABLE_NAME = "modRmOpcode";

    private void printSubroutine(IndentWriter writer, Template_Type template) {
        writer.print("(byte ");
        if (template.opcode2() != null) {
            writer.print(OPCODE2_VARIABLE_NAME);
        } else {
            writer.print(OPCODE1_VARIABLE_NAME);
        }
        if (template.modRMGroupOpcode() != null) {
            writer.print(", byte " + MODRM_GROUP_OPCODE_VARIABLE_NAME);
        }
        writer.print(formatParameterList(", ", template.parameters(), false));
        writer.println(") {");
        writer.indent();
        writer.indent();
        printModVariants(writer, template);
        printPrefixes(writer, template);
        if (template.opcode2() != null) {
            emitByte(writer, "(byte) (" + Bytes.toHexLiteral(template.opcode1().byteValue()) + ")");
            writer.println(" // " + OPCODE1_VARIABLE_NAME);
            printOpcode(writer, template, OPCODE2_VARIABLE_NAME, ParameterPlace.OPCODE2, ParameterPlace.OPCODE2_REXB);
        } else {
            printOpcode(writer, template, OPCODE1_VARIABLE_NAME, ParameterPlace.OPCODE1, ParameterPlace.OPCODE1_REXB);
        }
        if (template.hasModRMByte()) {
            printModRMByte(writer, template);
            if (template.hasSibByte()) {
                printSibByte(writer, template);
            } else {
                printSibVariants(writer, template);
            }
        }
        printAppendedParameter(writer, template);
        writer.outdent();
        writer.println("}");
        writer.outdent();
    }

    private String makeSubroutine(Template_Type template) {
        final StringWriter stringWriter = new StringWriter();
        printSubroutine(new IndentWriter(new PrintWriter(stringWriter)), template);
        final String subroutine = stringWriter.toString();
        String name = subroutineToName.get(subroutine);
        if (name == null) {
            name = createSubroutineName();
            subroutineToName.put(subroutine, name);
        }
        return name;
    }

    @Override
    protected int printMethod(IndentWriter writer, Template_Type template) {
        final int startLineCount = writer.lineCount();
        writer.print("public void ");
        writer.print(template.assemblerMethodName() + "(");
        writer.print(formatParameterList("", template.parameters(), false));
        writer.println(") {");
        writer.indent();
        final String subroutineName = makeSubroutine(template);
        writer.print(subroutineName + "(");
        if (template.opcode2() != null) {
            writer.print("(byte) " + Bytes.toHexLiteral(template.opcode2().byteValue()));
        } else {
            writer.print("(byte) " + Bytes.toHexLiteral(template.opcode1().byteValue()));
        }
        if (template.modRMGroupOpcode() != null) {
            writer.print(", (byte) " + Bytes.toHexLiteral(template.modRMGroupOpcode().byteValue()));
        }
        for (X86Parameter parameter : template.parameters()) {
            writer.print(", " + parameter.variableName());
        }
        writer.println(");");
        writer.outdent();
        writer.println("}");
        return writer.lineCount() - startLineCount;
    }

    @Override
    protected int printSubroutines(IndentWriter writer) {
        final Set<String> subroutineSet = subroutineToName.keySet();
        final String[] subroutines = subroutineSet.toArray(new String[subroutineSet.size()]);
        for (int i = 0; i < subroutines.length; i++) {
            subroutines[i] = subroutineToName.get(subroutines[i]) + subroutines[i];
        }
        java.util.Arrays.sort(subroutines);
        for (String subroutine : subroutines) {
            writer.print("private void " + subroutine);
            writer.println();
        }
        return subroutines.length;
    }

    private boolean parametersMatching(Template_Type candidate, Template_Type original) {
        if (candidate.parameters().size() != original.parameters().size()) {
            return false;
        }
        for (int i = 0; i < candidate.parameters().size(); i++) {
            if (i == original.labelParameterIndex()) {
                assert candidate.parameters().get(i).getClass() == X86OffsetParameter.class || candidate.parameters().get(i).getClass() == X86AddressParameter.class;
                assert candidate.parameters().get(i).getClass() == original.parameters().get(i).getClass();
            } else if (candidate.parameters().get(i).type() != original.parameters().get(i).type()) {
                return false;
            }
        }
        return true;
    }

    private final class LabelWidthCase {
        final WordWidth width;
        final Template_Type template;

        private LabelWidthCase(WordWidth width, Template_Type template) {
            this.width = width;
            this.template = template;
        }
    }

    private String getValidSizesMaskExpression(List<LabelWidthCase> labelWidthCases) {
        final Iterator<LabelWidthCase> iterator = labelWidthCases.iterator();
        String mask = String.valueOf(iterator.next().width.numberOfBytes);
        while (iterator.hasNext()) {
            mask += " | " + iterator.next().width.numberOfBytes;
        }
        return mask;
    }

    private List<LabelWidthCase> getRelatedLabelTemplatesByWidth(Template_Type template) {
        final List<LabelWidthCase> array = Utils.newArrayAsList(WordWidth.VALUES.size());
        for (Template_Type t : labelTemplates()) {
            if (t.assemblerMethodName().equals(template.assemblerMethodName()) && t.labelParameterIndex() == template.labelParameterIndex() && parametersMatching(t, template)) {
                final X86NumericalParameter numericalParameter = (X86NumericalParameter) t.parameters().get(template.labelParameterIndex());
                final WordWidth width = numericalParameter.width();
                array.set(width.ordinal(), new LabelWidthCase(width, t));
                t.isLabelMethodWritten = true;
            }
        }

        // Report the found cases in the order of ascending width:
        final List<LabelWidthCase> result = new LinkedList<LabelWidthCase>();
        for (int i = 0; i < array.size(); i++) {
            final LabelWidthCase labelWidthCase = array.get(i);
            if (labelWidthCase != null) {
                assert result.isEmpty() || labelWidthCase.width.greaterThan(Utils.last(result).width);
                result.add(labelWidthCase);
            }
        }
        assert result.size() > 0;
        return result;
    }

    private void printOffsetLabelMethod(final IndentWriter indentWriter,
                    Template_Type template,
                    final List<Parameter> parameters,
                    String assemblerClassName) {
        final List<LabelWidthCase> labelWidthCases = getRelatedLabelTemplatesByWidth(template);
        final InstructionWithLabelSubclass labelInstructionSubclass = new InstructionWithLabelSubclass(template, InstructionWithOffset.class, ", " + getValidSizesMaskExpression(labelWidthCases)) {
            @Override
            public void printAssembleMethodBody(IndentWriter writer, Template t) {
                if (labelWidthCases.size() == 1) {
                    final LabelWidthCase labelWidthCase = Utils.first(labelWidthCases);
                    super.printAssembleMethodBody(writer, labelWidthCase.template);
                } else {
                    writer.println("final int labelSize = labelSize();");
                    String prefix = "";
                    for (LabelWidthCase labelWidthCase : labelWidthCases) {
                        writer.println(prefix + "if (labelSize == " + labelWidthCase.width.numberOfBytes + ") {");
                        writer.indent();
                        super.printAssembleMethodBody(writer, labelWidthCase.template);
                        writer.outdent();
                        prefix = "} else ";
                    }
                    writer.println(prefix + "{");
                    writer.println("    throw new " + AssemblyException.class.getSimpleName() + "(\"Unexpected label width: \" + labelSize);");
                    writer.println("}");
                }
            }
        };

        printLabelMethodHelper(indentWriter,
                        template,
                        parameters,
                        -1,
                        assemblerClassName,
                        labelInstructionSubclass);
    }

    private void printAddressLabelMethod(
                    final IndentWriter indentWriter,
                    final Template_Type template,
                    final List<Parameter> parameters,
                    String assemblerClassName) {
        final InstructionWithLabelSubclass labelInstructionSubclass = new InstructionWithLabelSubclass(template, InstructionWithAddress.class, "");
        printLabelMethodHelper(indentWriter,
                        template,
                        parameters,
                        -1,
                        assemblerClassName,
                        labelInstructionSubclass);
    }

    @Override
    protected boolean omitLabelTemplate(Template_Type labelTemplate) {
        return labelTemplate.isLabelMethodWritten;
    }

    @Override
    protected void printLabelMethod(IndentWriter writer, Template_Type labelTemplate, String assemblerClassName) {
        if (labelTemplate.addressSizeAttribute() == addressWidth()) {
            if (!labelTemplate.isLabelMethodWritten) {
                labelTemplate.isLabelMethodWritten = true;
                final List<Parameter> parameters = getParameters(labelTemplate, true);
                final X86Parameter parameter = labelTemplate.parameters().get(labelTemplate.labelParameterIndex());
                if (parameter instanceof X86OffsetParameter) {
                    printOffsetLabelMethod(writer, labelTemplate, parameters, assemblerClassName);
                } else {
                    printAddressLabelMethod(writer, labelTemplate, parameters, assemblerClassName);
                }
            }
        }
    }

    public static byte basicRexValue(X86Template template) {
        if (template.operandSizeAttribute() == WordWidth.BITS_64 && template.instructionDescription().defaultOperandSize() != WordWidth.BITS_64) {
            return (byte) (X86Opcode.REX_MIN.ordinal() + (1 << X86Field.REX_W_BIT_INDEX));
        }
        return (byte) X86Opcode.REX_MIN.ordinal();
    }
}