/** * Computes the set of emit methods in the Assembler for a given IA32 opcode. * * @param emitters the set of all emit methods * @param opcode the opcode being examined */ private static EmitterSet buildSetForOpcode(Method[] emitters, String opcode) { EmitterSet s = new EmitterSet(); for (int i = 0; i < emitters.length; i++) { Method m = emitters[i]; if (m.getName().startsWith("emit" + opcode + "_") || m.getName().equals("emit" + opcode)) { s.add(new EmitterDescriptor(m.getName(), m.getParameterTypes())); } } return s; }
/** * This method uses a SplitRecord as the criertion to partition the given EmitterSet into two * subsets. * * @param split the plit record dicatating how to split */ private EmitterSet[] makeSplit(SplitRecord split) { int arg = split.argument; ArgumentType test = split.test; EmitterSet yes = new EmitterSet(); EmitterSet no = new EmitterSet(); Iterator<EmitterDescriptor> i = emitters.iterator(); while (i.hasNext()) { EmitterDescriptor ed = (EmitterDescriptor) i.next(); if (ed.argMatchesEncoding(arg, test)) { yes.add(ed); } else { no.add(ed); } } return new EmitterSet[] {yes, no}; }
/** 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); } }