comparison 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
comparison
equal deleted inserted replaced
3732:3e2e8b8abdaf 3733:e233f5660da4
1 /*
2 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package com.sun.max.asm.gen.cisc.x86;
24
25 import java.io.*;
26 import java.util.*;
27
28 import com.sun.max.*;
29 import com.sun.max.asm.*;
30 import com.sun.max.asm.gen.*;
31 import com.sun.max.io.*;
32 import com.sun.max.lang.*;
33 import com.sun.max.program.*;
34 import com.sun.max.program.option.*;
35
36 /**
37 */
38 public abstract class X86AssemblerGenerator<Template_Type extends X86Template> extends AssemblerGenerator<Template_Type> {
39
40 private final Option<Boolean> support16BitAddressesOption = options.newBooleanOption("a16", false, "Enables 16 bit addressing.");
41 private final Option<Boolean> support16BitOffsetOption = options.newBooleanOption("d16", false, "Enables 16 bit offsets.");
42
43 private final WordWidth addressWidth;
44
45 protected X86AssemblerGenerator(Assembly<Template_Type> assembly, WordWidth addressWidth) {
46 super(assembly, true);
47 this.addressWidth = addressWidth;
48 }
49
50 @Override
51 public X86Assembly<Template_Type> assembly() {
52 final Class<X86Assembly<Template_Type>> type = null;
53 return Utils.cast(type, super.assembly());
54 }
55
56 public WordWidth addressWidth() {
57 return addressWidth;
58 }
59
60 @Override
61 protected void generate() {
62 if (support16BitAddressesOption.getValue() != null && support16BitAddressesOption.getValue()) {
63 X86Assembly.support16BitAddresses();
64 }
65 if (support16BitOffsetOption.getValue() != null && support16BitOffsetOption.getValue()) {
66 X86Assembly.support16BitOffsets();
67 }
68 super.generate();
69 }
70
71 protected X86Parameter getParameter(Template_Type template, Class parameterType) {
72 for (X86Parameter parameter : template.parameters()) {
73 if (parameter.type() == parameterType) {
74 return parameter;
75 }
76 }
77 throw ProgramError.unexpected("found no parameter of type: " + parameterType);
78 }
79
80 private void printCallWithByteDisplacement(IndentWriter writer, Template_Type template, Class argumentType) {
81 final Template_Type modVariantTemplate = X86Assembly.getModVariantTemplate(assembly().templates(), template, argumentType);
82 final String subroutineName = makeSubroutine(modVariantTemplate);
83 writer.print(subroutineName + "(");
84 if (template.opcode2() != null) {
85 writer.print(OPCODE2_VARIABLE_NAME);
86 } else {
87 writer.print(OPCODE1_VARIABLE_NAME);
88 }
89 if (template.modRMGroupOpcode() != null) {
90 writer.print(", " + MODRM_GROUP_OPCODE_VARIABLE_NAME);
91 }
92 for (X86Parameter parameter : template.parameters()) {
93 if (parameter.type() == argumentType) {
94 writer.print(", (byte) 0");
95 }
96 writer.print(", " + parameter.variableName());
97 }
98 writer.println(");");
99 }
100
101 protected String asIdentifier(EnumerableArgument argument) {
102 return argument.getClass().getSimpleName() + "." + argument.name();
103 }
104
105 protected <Argument_Type extends Enum<Argument_Type> & EnumerableArgument<Argument_Type>> void printModVariant(IndentWriter writer, final Template_Type template, Argument_Type... arguments) {
106 final Class argumentType = arguments[0].getClass();
107 final X86Parameter parameter = getParameter(template, argumentType);
108 writer.print("if (");
109 String separator = "";
110 for (EnumerableArgument argument : arguments) {
111 writer.print(separator + parameter.variableName() + " == " + asIdentifier(argument));
112 separator = " || ";
113 }
114 writer.println(") {");
115 writer.indent();
116 printCallWithByteDisplacement(writer, template, argumentType);
117 writer.println("return;");
118 writer.outdent();
119 writer.println("}");
120 }
121
122 protected abstract void printModVariants(IndentWriter writer, Template_Type template);
123
124 protected void printPrefixes(IndentWriter writer, Template_Type template) {
125 if (template.addressSizeAttribute() != addressWidth()) {
126 emitByte(writer, X86Opcode.ADDRESS_SIZE.byteValue());
127 writer.println(" // address size prefix");
128 }
129 if (template.operandSizeAttribute() == WordWidth.BITS_16) {
130 emitByte(writer, X86Opcode.OPERAND_SIZE.byteValue());
131 writer.println(" // operand size prefix");
132 }
133 if (template.instructionSelectionPrefix() != null) {
134 emitByte(writer, template.instructionSelectionPrefix().byteValue());
135 writer.println(" // instruction selection prefix");
136 }
137 }
138
139 private void printOpcode(IndentWriter writer, Template_Type template, String opcodeVarName, final ParameterPlace parameterPlace32, ParameterPlace parameterPlace64) {
140 String comment = "";
141 String opcodeVariableName = opcodeVarName;
142 for (X86Parameter parameter : template.parameters()) {
143 if (parameter.place() == parameterPlace32) {
144 opcodeVariableName += " + " + parameter.valueString();
145 comment = " // " + parameterPlace32.name().toLowerCase();
146 } else if (parameter.place() == parameterPlace64) {
147 opcodeVariableName += " + (" + parameter.valueString() + "& 7)";
148 comment = " // " + parameterPlace64.name().toLowerCase();
149 }
150 }
151 if (comment.length() == 0) {
152 emitByte(writer, opcodeVariableName);
153 writer.println();
154 } else {
155 emitByte(writer, "(byte) (" + opcodeVariableName + ")");
156 writer.println(comment);
157 }
158 }
159
160 private static final String MODRM_BYTE_VARIABLE_NAME = "modRMByte";
161
162 private void printModRMByte(IndentWriter writer, Template_Type template) {
163 writer.print("byte " + MODRM_BYTE_VARIABLE_NAME + " = (byte) ((" + template.modCase().ordinal() + " << " + X86Field.MOD.shift() + ")");
164 if (template.modRMGroupOpcode() != null) {
165 writer.print(" | (" + MODRM_GROUP_OPCODE_VARIABLE_NAME + " << " + X86Field.REG.shift() + ")");
166 }
167 writer.print("); // mod field");
168 if (template.modRMGroupOpcode() != null) {
169 writer.print(", group opcode in reg field");
170 }
171 writer.println();
172 switch (template.rmCase()) {
173 case SIB:
174 case SWORD:
175 case SDWORD: {
176 writer.println(MODRM_BYTE_VARIABLE_NAME + " |= " + template.rmCase().value() + " << " + X86Field.RM.shift() + "; // rm field");
177 break;
178 }
179 default:
180 break;
181 }
182 for (X86Parameter parameter : template.parameters()) {
183 switch (parameter.place()) {
184 case MOD_REG:
185 case MOD_REG_REXR: {
186 writer.println(MODRM_BYTE_VARIABLE_NAME + " |= (" + parameter.valueString() + " & 7) << " + X86Field.REG.shift() + "; // reg field");
187 break;
188 }
189 case MOD_RM:
190 case MOD_RM_REXB: {
191 writer.println(MODRM_BYTE_VARIABLE_NAME + " |= (" + parameter.valueString() + " & 7) << " + X86Field.RM.shift() + "; // rm field");
192 break;
193 }
194 default:
195 break;
196 }
197 }
198 emitByte(writer, MODRM_BYTE_VARIABLE_NAME);
199 writer.println();
200 }
201
202 private static final String SIB_BYTE_NAME = "sibByte";
203
204 private void printSibByte(IndentWriter writer, Template_Type template) {
205 writer.print("byte " + SIB_BYTE_NAME + " = ");
206 if (template.sibBaseCase() == X86TemplateContext.SibBaseCase.SPECIAL) {
207 writer.println("(byte) (5 << " + X86Field.BASE.shift() + "); // base field");
208 } else {
209 writer.println("(byte) 0;");
210 }
211 for (X86Parameter parameter : template.parameters()) {
212 switch (parameter.place()) {
213 case SIB_BASE:
214 case SIB_BASE_REXB:
215 writer.println(SIB_BYTE_NAME + " |= (" + parameter.valueString() + " & 7) << " + X86Field.BASE.shift() + "; // base field");
216 break;
217 case SIB_INDEX:
218 case SIB_INDEX_REXX:
219 writer.println(SIB_BYTE_NAME + " |= (" + parameter.valueString() + " & 7) << " + X86Field.INDEX.shift() + "; // index field");
220 break;
221 case SIB_SCALE:
222 writer.println(SIB_BYTE_NAME + " |= " + parameter.valueString() + " << " + X86Field.SCALE.shift() + "; // scale field");
223 break;
224 default:
225 break;
226 }
227 }
228 emitByte(writer, SIB_BYTE_NAME);
229 writer.println();
230 }
231
232 protected <Argument_Type extends Enum<Argument_Type> & EnumerableArgument<Argument_Type>> void printSibVariant(IndentWriter writer, Template_Type template, Argument_Type... arguments) {
233 final Class argumentType = arguments[0].getClass();
234 final X86Parameter parameter = getParameter(template, argumentType);
235 writer.print("if (");
236 String separator = "";
237 for (EnumerableArgument argument : arguments) {
238 writer.print(separator + parameter.variableName() + " == " + asIdentifier(argument));
239 separator = " || ";
240 }
241 writer.println(") {");
242 writer.indent();
243 emitByte(writer, (byte) 0x24);
244 writer.println(" // SIB byte");
245 writer.outdent();
246 writer.println("}");
247 }
248
249 protected abstract void printSibVariants(IndentWriter writer, Template_Type template);
250
251 private void printImmediateParameter(IndentWriter writer, X86NumericalParameter parameter) {
252 if (parameter.width() == WordWidth.BITS_8) {
253 emitByte(writer, parameter.variableName());
254 writer.println(" // appended");
255 } else {
256 writer.println("// appended:");
257 for (int i = 0; i < parameter.width().numberOfBytes; i++) {
258 if (i > 0) {
259 writer.println(parameter.variableName() + " >>= 8;");
260 }
261 emitByte(writer, "(byte) (" + parameter.variableName() + " & 0xff)");
262 writer.println();
263 }
264 }
265 }
266
267 private void printAppendedEnumerableParameter(IndentWriter writer, X86EnumerableParameter parameter) {
268 emitByte(writer, "(byte) " + parameter.variableName() + ".value()");
269 writer.println(" // appended");
270 }
271
272 private void printAppendedParameter(IndentWriter writer, Template_Type template) {
273 for (X86Parameter parameter : template.parameters()) {
274 if (parameter.place() == ParameterPlace.APPEND) {
275 if (parameter instanceof X86NumericalParameter) {
276 printImmediateParameter(writer, (X86NumericalParameter) parameter);
277 } else if (parameter instanceof X86EnumerableParameter) {
278 printAppendedEnumerableParameter(writer, (X86EnumerableParameter) parameter);
279 } else {
280 throw ProgramError.unexpected("appended parameter of unexpected type: " + parameter);
281 }
282 }
283 }
284 }
285
286 private int subroutineSerial;
287
288 private String createSubroutineName() {
289 ++subroutineSerial;
290 String number = Integer.toString(subroutineSerial);
291 while (number.length() < 4) {
292 number = "0" + number;
293 }
294 return "assemble" + number;
295 }
296
297 private Map<String, String> subroutineToName = new HashMap<String, String>();
298
299 private static final String OPCODE1_VARIABLE_NAME = "opcode1";
300 private static final String OPCODE2_VARIABLE_NAME = "opcode2";
301 private static final String MODRM_GROUP_OPCODE_VARIABLE_NAME = "modRmOpcode";
302
303 private void printSubroutine(IndentWriter writer, Template_Type template) {
304 writer.print("(byte ");
305 if (template.opcode2() != null) {
306 writer.print(OPCODE2_VARIABLE_NAME);
307 } else {
308 writer.print(OPCODE1_VARIABLE_NAME);
309 }
310 if (template.modRMGroupOpcode() != null) {
311 writer.print(", byte " + MODRM_GROUP_OPCODE_VARIABLE_NAME);
312 }
313 writer.print(formatParameterList(", ", template.parameters(), false));
314 writer.println(") {");
315 writer.indent();
316 writer.indent();
317 printModVariants(writer, template);
318 printPrefixes(writer, template);
319 if (template.opcode2() != null) {
320 emitByte(writer, "(byte) (" + Bytes.toHexLiteral(template.opcode1().byteValue()) + ")");
321 writer.println(" // " + OPCODE1_VARIABLE_NAME);
322 printOpcode(writer, template, OPCODE2_VARIABLE_NAME, ParameterPlace.OPCODE2, ParameterPlace.OPCODE2_REXB);
323 } else {
324 printOpcode(writer, template, OPCODE1_VARIABLE_NAME, ParameterPlace.OPCODE1, ParameterPlace.OPCODE1_REXB);
325 }
326 if (template.hasModRMByte()) {
327 printModRMByte(writer, template);
328 if (template.hasSibByte()) {
329 printSibByte(writer, template);
330 } else {
331 printSibVariants(writer, template);
332 }
333 }
334 printAppendedParameter(writer, template);
335 writer.outdent();
336 writer.println("}");
337 writer.outdent();
338 }
339
340 private String makeSubroutine(Template_Type template) {
341 final StringWriter stringWriter = new StringWriter();
342 printSubroutine(new IndentWriter(new PrintWriter(stringWriter)), template);
343 final String subroutine = stringWriter.toString();
344 String name = subroutineToName.get(subroutine);
345 if (name == null) {
346 name = createSubroutineName();
347 subroutineToName.put(subroutine, name);
348 }
349 return name;
350 }
351
352 @Override
353 protected int printMethod(IndentWriter writer, Template_Type template) {
354 final int startLineCount = writer.lineCount();
355 writer.print("public void ");
356 writer.print(template.assemblerMethodName() + "(");
357 writer.print(formatParameterList("", template.parameters(), false));
358 writer.println(") {");
359 writer.indent();
360 final String subroutineName = makeSubroutine(template);
361 writer.print(subroutineName + "(");
362 if (template.opcode2() != null) {
363 writer.print("(byte) " + Bytes.toHexLiteral(template.opcode2().byteValue()));
364 } else {
365 writer.print("(byte) " + Bytes.toHexLiteral(template.opcode1().byteValue()));
366 }
367 if (template.modRMGroupOpcode() != null) {
368 writer.print(", (byte) " + Bytes.toHexLiteral(template.modRMGroupOpcode().byteValue()));
369 }
370 for (X86Parameter parameter : template.parameters()) {
371 writer.print(", " + parameter.variableName());
372 }
373 writer.println(");");
374 writer.outdent();
375 writer.println("}");
376 return writer.lineCount() - startLineCount;
377 }
378
379 @Override
380 protected int printSubroutines(IndentWriter writer) {
381 final Set<String> subroutineSet = subroutineToName.keySet();
382 final String[] subroutines = subroutineSet.toArray(new String[subroutineSet.size()]);
383 for (int i = 0; i < subroutines.length; i++) {
384 subroutines[i] = subroutineToName.get(subroutines[i]) + subroutines[i];
385 }
386 java.util.Arrays.sort(subroutines);
387 for (String subroutine : subroutines) {
388 writer.print("private void " + subroutine);
389 writer.println();
390 }
391 return subroutines.length;
392 }
393
394 private boolean parametersMatching(Template_Type candidate, Template_Type original) {
395 if (candidate.parameters().size() != original.parameters().size()) {
396 return false;
397 }
398 for (int i = 0; i < candidate.parameters().size(); i++) {
399 if (i == original.labelParameterIndex()) {
400 assert candidate.parameters().get(i).getClass() == X86OffsetParameter.class || candidate.parameters().get(i).getClass() == X86AddressParameter.class;
401 assert candidate.parameters().get(i).getClass() == original.parameters().get(i).getClass();
402 } else if (candidate.parameters().get(i).type() != original.parameters().get(i).type()) {
403 return false;
404 }
405 }
406 return true;
407 }
408
409 private final class LabelWidthCase {
410 final WordWidth width;
411 final Template_Type template;
412
413 private LabelWidthCase(WordWidth width, Template_Type template) {
414 this.width = width;
415 this.template = template;
416 }
417 }
418
419 private String getValidSizesMaskExpression(List<LabelWidthCase> labelWidthCases) {
420 final Iterator<LabelWidthCase> iterator = labelWidthCases.iterator();
421 String mask = String.valueOf(iterator.next().width.numberOfBytes);
422 while (iterator.hasNext()) {
423 mask += " | " + iterator.next().width.numberOfBytes;
424 }
425 return mask;
426 }
427
428 private List<LabelWidthCase> getRelatedLabelTemplatesByWidth(Template_Type template) {
429 final List<LabelWidthCase> array = Utils.newArrayAsList(WordWidth.VALUES.size());
430 for (Template_Type t : labelTemplates()) {
431 if (t.assemblerMethodName().equals(template.assemblerMethodName()) && t.labelParameterIndex() == template.labelParameterIndex() && parametersMatching(t, template)) {
432 final X86NumericalParameter numericalParameter = (X86NumericalParameter) t.parameters().get(template.labelParameterIndex());
433 final WordWidth width = numericalParameter.width();
434 array.set(width.ordinal(), new LabelWidthCase(width, t));
435 t.isLabelMethodWritten = true;
436 }
437 }
438
439 // Report the found cases in the order of ascending width:
440 final List<LabelWidthCase> result = new LinkedList<LabelWidthCase>();
441 for (int i = 0; i < array.size(); i++) {
442 final LabelWidthCase labelWidthCase = array.get(i);
443 if (labelWidthCase != null) {
444 assert result.isEmpty() || labelWidthCase.width.greaterThan(Utils.last(result).width);
445 result.add(labelWidthCase);
446 }
447 }
448 assert result.size() > 0;
449 return result;
450 }
451
452 private void printOffsetLabelMethod(final IndentWriter indentWriter,
453 Template_Type template,
454 final List<Parameter> parameters,
455 String assemblerClassName) {
456 final List<LabelWidthCase> labelWidthCases = getRelatedLabelTemplatesByWidth(template);
457 final InstructionWithLabelSubclass labelInstructionSubclass = new InstructionWithLabelSubclass(template, InstructionWithOffset.class, ", " + getValidSizesMaskExpression(labelWidthCases)) {
458 @Override
459 public void printAssembleMethodBody(IndentWriter writer, Template t) {
460 if (labelWidthCases.size() == 1) {
461 final LabelWidthCase labelWidthCase = Utils.first(labelWidthCases);
462 super.printAssembleMethodBody(writer, labelWidthCase.template);
463 } else {
464 writer.println("final int labelSize = labelSize();");
465 String prefix = "";
466 for (LabelWidthCase labelWidthCase : labelWidthCases) {
467 writer.println(prefix + "if (labelSize == " + labelWidthCase.width.numberOfBytes + ") {");
468 writer.indent();
469 super.printAssembleMethodBody(writer, labelWidthCase.template);
470 writer.outdent();
471 prefix = "} else ";
472 }
473 writer.println(prefix + "{");
474 writer.println(" throw new " + AssemblyException.class.getSimpleName() + "(\"Unexpected label width: \" + labelSize);");
475 writer.println("}");
476 }
477 }
478 };
479
480 printLabelMethodHelper(indentWriter,
481 template,
482 parameters,
483 -1,
484 assemblerClassName,
485 labelInstructionSubclass);
486 }
487
488 private void printAddressLabelMethod(
489 final IndentWriter indentWriter,
490 final Template_Type template,
491 final List<Parameter> parameters,
492 String assemblerClassName) {
493 final InstructionWithLabelSubclass labelInstructionSubclass = new InstructionWithLabelSubclass(template, InstructionWithAddress.class, "");
494 printLabelMethodHelper(indentWriter,
495 template,
496 parameters,
497 -1,
498 assemblerClassName,
499 labelInstructionSubclass);
500 }
501
502 @Override
503 protected boolean omitLabelTemplate(Template_Type labelTemplate) {
504 return labelTemplate.isLabelMethodWritten;
505 }
506
507 @Override
508 protected void printLabelMethod(IndentWriter writer, Template_Type labelTemplate, String assemblerClassName) {
509 if (labelTemplate.addressSizeAttribute() == addressWidth()) {
510 if (!labelTemplate.isLabelMethodWritten) {
511 labelTemplate.isLabelMethodWritten = true;
512 final List<Parameter> parameters = getParameters(labelTemplate, true);
513 final X86Parameter parameter = labelTemplate.parameters().get(labelTemplate.labelParameterIndex());
514 if (parameter instanceof X86OffsetParameter) {
515 printOffsetLabelMethod(writer, labelTemplate, parameters, assemblerClassName);
516 } else {
517 printAddressLabelMethod(writer, labelTemplate, parameters, assemblerClassName);
518 }
519 }
520 }
521 }
522
523 public static byte basicRexValue(X86Template template) {
524 if (template.operandSizeAttribute() == WordWidth.BITS_64 && template.instructionDescription().defaultOperandSize() != WordWidth.BITS_64) {
525 return (byte) (X86Opcode.REX_MIN.ordinal() + (1 << X86Field.REX_W_BIT_INDEX));
526 }
527 return (byte) X86Opcode.REX_MIN.ordinal();
528 }
529 }