Mercurial > hg > truffle
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.asmdis/src/com/sun/max/asm/gen/cisc/x86/X86AssemblerGenerator.java Sat Dec 17 19:59:18 2011 +0100 @@ -0,0 +1,529 @@ +/* + * 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(); + } +}