/** * For a given string representing a valid operand encoding for the Assembler, return the * corresponding Assembler constant. This function only looks for encodings of operand types, and * will not accept strings that correspond to size encodings. * * @param str A valid Assembler encoding of operand type * @return The Assembler constant corresponding to str, or -1 if none */ private static ArgumentType getEncoding(String str, Class<?> type) { if (str.equals("Reg")) { if (type == null) { throw new Error("Unable to encode Reg with no type information"); } String typeName = type.getName(); str = typeName.substring(typeName.lastIndexOf('$') + 1) + "_Reg"; } for (ArgumentType arg : ArgumentType.values()) { if (arg.getOptName().equals(str)) { return arg; } } throw new Error( "Unable to encode the argument " + str + " of type " + type + " as a valid argument type"); }
/** * Find the best operand type or size and operand number to partition this EmitterSet. This * method searches across all possible ways of splitting this set--all possible operand types * and sizes, and all possible operands--to determine which one splits the set most evenly. * * @return a SplitRecord representing the most-even split */ SplitRecord split() { int splitArg = -1; ArgumentType splitTest = null; int splitDiff = 1000; for (int arg = 0; arg < 4; arg++) { for (ArgumentType test : ArgumentType.values()) { int c = getEncodingSplit(arg, test); if (c == 0) return new SplitRecord(arg, test); else if (c < splitDiff) { splitArg = arg; splitTest = test; splitDiff = c; } } } return new SplitRecord(splitArg, splitTest); }
/** Generate an assembler for the opt compiler */ public static void main(String[] args) { try { out = new FileWriter(System.getProperty("generateToDir") + "/AssemblerOpt.java"); } catch (IOException e) { throw new Error(e); } emit("package org.jikesrvm.compilers.opt.mir2mc.ia32;\n\n"); emit("import org.jikesrvm.*;\n\n"); emit("import org.jikesrvm.compilers.opt.*;\n\n"); emit("import org.jikesrvm.compilers.opt.ir.*;\n\n"); emit("import org.jikesrvm.compilers.opt.ir.ia32.*;\n\n"); emit("import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.*;\n\n"); emit("import static org.jikesrvm.compilers.opt.OptimizingCompilerException.opt_assert;\n\n"); emit("\n\n"); emit("/**\n"); emit(" * This class is the automatically-generated assembler for\n"); emit(" * the optimizing compiler. It consists of methods that\n"); emit(" * understand the possible operand combinations of each\n"); emit(" * instruction type, and how to translate those operands to\n"); emit(" * calls to the Assember low-level emit method\n"); emit(" *\n"); emit(" * It is generated by GenerateAssembler.java\n"); emit(" *\n"); emit(" */\n"); emit("public class AssemblerOpt extends AssemblerBase {\n\n"); emitTab(1); emit("/**\n"); emitTab(1); emit(" * @see org.jikesrvm.ArchitectureSpecific.Assembler\n"); emitTab(1); emit(" */\n"); emitTab(1); emit("public AssemblerOpt(int bcSize, boolean print, IR ir) {\n"); emitTab(2); emit("super(bcSize, print, ir);\n"); emitTab(1); emit("}"); emit("\n\n"); Method[] emitters = lowLevelAsm.getDeclaredMethods(); Set<String> opcodes = getOpcodes(emitters); Iterator<String> i = opcodes.iterator(); while (i.hasNext()) { String opcode = (String) i.next(); setCurrentOpcode(opcode); emitTab(1); emit("/**\n"); emitTab(1); emit(" * Emit the given instruction, assuming that\n"); emitTab(1); emit(" * it is a " + currentFormat + " instruction\n"); emitTab(1); emit(" * and has a " + currentOpcode + " operator\n"); emitTab(1); emit(" *\n"); emitTab(1); emit(" * @param inst the instruction to assemble\n"); emitTab(1); emit(" */\n"); emitTab(1); emit("private void do" + opcode + "(Instruction inst) {\n"); EmitterSet emitter = buildSetForOpcode(emitters, opcode); boolean[][] tp = new boolean[4][ArgumentType.values().length]; emitter.emitSet(opcode, tp, 2); emitTab(1); emit("}\n\n"); } emitTab(1); emit("/**\n"); emitTab(1); emit(" * The number of instructions emitted so far\n"); emitTab(1); emit(" */\n"); emitTab(1); emit("private int instructionCount = 0;\n\n"); emitTab(1); emit("/**\n"); emitTab(1); emit(" * Assemble the given instruction\n"); emitTab(1); emit(" *\n"); emitTab(1); emit(" * @param inst the instruction to assemble\n"); emitTab(1); emit(" */\n"); emitTab(1); emit("public void doInst(Instruction inst) {\n"); emitTab(2); emit("instructionCount++;\n"); emitTab(2); emit("resolveForwardReferences(instructionCount);\n"); emitTab(2); emit("switch (inst.getOpcode()) {\n"); Set<String> emittedOpcodes = new HashSet<String>(); i = opcodes.iterator(); while (i.hasNext()) { String opcode = i.next(); Iterator<String> operators = getMatchingOperators(opcode).iterator(); while (operators.hasNext()) { String operator = operators.next(); emitTab(3); emittedOpcodes.add(operator); emit("case IA32_" + operator + "_opcode:\n"); } emitTab(4); emit("do" + opcode + "(inst);\n"); emitTab(4); emit("break;\n"); } // Special case because doJCC is handwritten to add // logic for short-forward branches emittedOpcodes.add("JCC"); emitTab(3); emit("case IA32_JCC_opcode:\n"); emitTab(4); emit("doJCC(inst);\n"); emitTab(4); emit("break;\n"); // Special case because doJMP is handwritten to add // logic for short-forward branches emittedOpcodes.add("JMP"); emitTab(3); emit("case IA32_JMP_opcode:\n"); emitTab(4); emit("doJMP(inst);\n"); emitTab(4); emit("break;\n"); // Kludge for IA32_LOCK which needs to call emitLockNextInstruction emittedOpcodes.add("LOCK"); emitTab(3); emit("case IA32_LOCK_opcode:\n"); emitTab(4); emit("emitLockNextInstruction();\n"); emitTab(4); emit("break;\n"); // Kludge for PATCH_POINT emitTab(3); emit("case IG_PATCH_POINT_opcode:\n"); emitTab(4); emit("emitPatchPoint();\n"); emitTab(4); emit("break;\n"); // Kludge for LOWTABLESWITCH emitTab(3); emit("case MIR_LOWTABLESWITCH_opcode:\n"); emitTab(4); emit("doLOWTABLESWITCH(inst);\n"); emitTab(4); emit("// kludge table switches that are unusually long instructions\n"); emitTab(4); emit("instructionCount += MIR_LowTableSwitch.getNumberOfTargets(inst);\n"); emitTab(4); emit("break;\n"); Set<String> errorOpcodes = getErrorOpcodes(emittedOpcodes); if (!errorOpcodes.isEmpty()) { i = errorOpcodes.iterator(); while (i.hasNext()) { emitTab(3); emit("case IA32_" + i.next() + "_opcode:\n"); } emitTab(4); emit( "throw new OptimizingCompilerException(inst + \" has unimplemented IA32 opcode (check excludedOpcodes)\");\n"); } emitTab(2); emit("}\n"); emitTab(2); emit("inst.setmcOffset( mi );\n"); emitTab(1); emit("}\n\n"); emit("\n}\n"); try { out.close(); } catch (IOException e) { throw new Error(e); } }