/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.vm.compiler.ir;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import org.jnode.assembler.x86.X86Assembler;
import org.jnode.assembler.x86.X86BinaryAssembler;
import org.jnode.assembler.x86.X86Constants;
import org.jnode.assembler.x86.X86Register;
import org.jnode.assembler.x86.X86TextAssembler;
import org.jnode.vm.VmImpl;
import org.jnode.vm.VmSystemClassLoader;
import org.jnode.vm.bytecode.BytecodeParser;
import org.jnode.vm.bytecode.BytecodeViewer;
import org.jnode.vm.classmgr.VmByteCode;
import org.jnode.vm.classmgr.VmMethod;
import org.jnode.vm.classmgr.VmType;
import org.jnode.vm.compiler.CompiledMethod;
import org.jnode.vm.compiler.EntryPoints;
import org.jnode.vm.compiler.ir.quad.Quad;
import org.jnode.vm.facade.TypeSizeInfo;
import org.jnode.vm.facade.VmUtils;
import org.jnode.vm.x86.VmX86Architecture32;
import org.jnode.vm.x86.X86CpuID;
import org.jnode.vm.x86.compiler.X86CompilerHelper;
import org.jnode.vm.x86.compiler.l2.X86CodeGenerator;
import org.jnode.vm.x86.compiler.l2.X86Level2Compiler;
import org.jnode.vm.x86.compiler.l2.X86StackFrame;
/**
* @author Madhu Siddalingaiah
* @author Levente S\u00e1ntha
*/
public class IRTest {
public static void main(String args[]) throws SecurityException, IOException, ClassNotFoundException,
InstantiationException {
// System.in.read();
X86CpuID cpuId = X86CpuID.createID("p5");
boolean binary = false;
String className = "org.jnode.vm.compiler.ir.PrimitiveTest";
// String className = "org.jnode.games.tetris.Tetris";
if (args.length > 0) {
String arg0 = args[0];
if ("-b".equals(arg0)) {
binary = true;
if (args.length > 1) {
className = args[1];
}
} else {
className = arg0;
}
}
if (binary) {
X86BinaryAssembler os = new X86BinaryAssembler(cpuId, X86Constants.Mode.CODE32, 0);
generateCode(os, className);
FileOutputStream fos = new FileOutputStream("test.bin");
os.writeTo(fos);
fos.close();
} else {
X86TextAssembler tos =
new X86TextAssembler(new OutputStreamWriter(System.out), cpuId, X86Constants.Mode.CODE32);
generateCode(tos, className);
tos.flush();
}
/*
BytecodeViewer bv = new BytecodeViewer();
BytecodeParser.parse(code, bv);
// System.out.println(cfg.toString());
// System.out.println();
boolean printDeadCode = false;
boolean printDetail = false;
IRBasicBlock currentBlock = null;
for (int i=0; i<n; i+=1) {
Quad quad = (Quad) quads.get(i);
if (currentBlock != quad.getBasicBlock()) {
currentBlock = quad.getBasicBlock();
System.out.println();
System.out.println(currentBlock);
}
if (printDeadCode && quad.isDeadCode()) {
if (printDetail) {
printQuadDetail(quad);
}
System.out.println(quad);
}
if (!quad.isDeadCode()) {
if (printDetail) {
printQuadDetail(quad);
}
System.out.println(quad);
}
}
System.out.println();
System.out.println("Live ranges:");
n = lv.size();
for (int i=0; i<n; i+=1) {
System.out.println(liveRanges[i]);
}
*/
}
private static void generateCode(X86Assembler os, String className)
throws MalformedURLException, ClassNotFoundException, InstantiationException {
//VmByteCode code = loadByteCode(className, "discriminant");
//VmByteCode code = loadByteCode(className, "arithOptIntx");
//VmByteCode code = loadByteCode(className, "simpleWhile");
//VmByteCode code = loadByteCode(className, "terniary2");
// VmByteCode code = loadByteCode(className, "trivial1");
// VmByteCode code = loadByteCode(className, "discriminant");
// VmByteCode code = loadByteCode(className, "arithOptLoop");
//VmByteCode code = loadByteCode(className, "discriminant");
//VmByteCode code = loadByteCode(className, "arithOptIntx");
//VmByteCode code = loadByteCode(className, "simpleWhile");
//VmByteCode code = loadByteCode(className, "terniary2");
VmX86Architecture32 arch = new VmX86Architecture32();
VmSystemClassLoader loader = new VmSystemClassLoader(new URL[]{
new File("core/build/classes").toURL(),
new File("distr/build/classes").toURL(),
new File("local/classlib").toURL()
}, arch);
new VmImpl("?", arch, loader.getSharedStatics(), true, loader, null);
VmType.initializeForBootImage(loader);
VmType<?> type = loader.loadClass(className, true);
VmMethod arithMethod = null;
int nMethods = type.getNoDeclaredMethods();
for (int i = 0; i < nMethods; i += 1) {
VmMethod method1 = type.getDeclaredMethod(i);
if ("terniary22".equals(method1.getName())) {
// if ("darken".equals(method1.getName())) {
arithMethod = method1;
break;
}
}
VmMethod method = arithMethod;
VmByteCode code = method.getBytecode();
//VmByteCode code = loadByteCode(className, "appel");
EntryPoints context = new EntryPoints(loader, VmUtils.getVm().getHeapManager(), 1);
X86CompilerHelper helper = new X86CompilerHelper(os, null, context, true);
CompiledMethod cm = new CompiledMethod(1);
TypeSizeInfo typeSizeInfo = loader.getArchitecture().getTypeSizeInfo();
helper.setMethod(method);
X86StackFrame stackFrame = new X86StackFrame(os, helper, method, context, cm);
X86CodeGenerator x86cg = new X86CodeGenerator(method, os, code.getLength(), typeSizeInfo, stackFrame);
generateCode(os, code, x86cg, stackFrame, arithMethod, typeSizeInfo);
// X86CodeGenerator x86cg = null;//new X86CodeGenerator(os, code.getLength());
//
// generateCode(os, code, x86cg);
}
private static <T extends X86Register> void generateCode(X86Assembler os, VmByteCode code, CodeGenerator<T> cg,
X86StackFrame stackFrame, VmMethod arithMethod,
TypeSizeInfo typeSizeInfo)
throws MalformedURLException, ClassNotFoundException {
IRControlFlowGraph<T> cfg = new IRControlFlowGraph<T>(code);
BytecodeViewer bv = new BytecodeViewer();
BytecodeParser.parse(code, bv);
System.out.println(cfg.toString());
System.out.println();
//System.out.println(cfg);
IRGenerator<T> irg = new IRGenerator<T>(cfg, typeSizeInfo, arithMethod.getDeclaringClass().getLoader());
BytecodeParser.parse(code, irg);
X86Level2Compiler.initMethodArguments(arithMethod, stackFrame, typeSizeInfo, irg);
printCFG(cfg, "Initial IR");
cfg.constructSSA();
printCFG(cfg, "Constructed SSA");
cfg.optimize();
printCFG(cfg, "Optimized SSA (pass 2)");
cfg.removeUnusedVars();
printCFG(cfg, "Unused vars removed SSA");
cfg.deconstrucSSA();
cfg.fixupAddresses();
printCFG(cfg, "Deconstructed SSA");
cfg.removeDefUseChains();
cfg.fixupAddresses();
printCFG(cfg, "Def-use chains removed SSA");
// removeUnusedVars(cfg);
// printCFG(cfg, "Unused vars removed SSA");
cfg.fixupAddresses();
List liveVariables = cfg.computeLiveVariables();
// System.out.println();
// cfg.optimize(liveVariables.values());
// printCFG(cfg, "Optimized SSA (pass 3)");
System.out.println("Live ranges:");
LiveRange<?>[] liveRanges = X86Level2Compiler.getLiveRanges(liveVariables);
LinearScanAllocator<?> lsa = X86Level2Compiler.allocate(liveRanges);
for (LiveRange range : liveRanges) {
System.out.println(range);
}
System.out.println();
X86Level2Compiler.generateCode(cg, cfg, irg, lsa);
// TODO
// 1. Fix method argument location, allocator leaves it null and breaks
// 2. Many necessary operations are not implemented in the code generator
// 3. Do something about unused phi nodes, they just waste space right now
// BootableArrayList quads = irg.getQuadList();
// int n = quads.size();
// BootableHashMap liveVariables = new BootableHashMap();
// for (int i=0; i<n; i+=1) {
// Quad quad = (Quad) quads.get(i);
//// System.out.println(quad);
// quad.doPass2(liveVariables);
// System.out.println(quad);
// }
// Collection lv = liveVariables.values();
// n = lv.size();
// LiveRange[] liveRanges = new LiveRange[n];
// Iterator it = lv.iterator();
// for (int i=0; i<n; i+=1) {
// Variable v = (Variable) it.next();
// liveRanges[i] = new LiveRange(v);
// // System.out.println("Live range: " + liveRanges[i]);
// }
// Arrays.sort(liveRanges);
// System.out.println(Arrays.asList(liveRanges));
// LinearScanAllocator lsa = new LinearScanAllocator(liveRanges);
// lsa.allocate();
//
// x86cg.setArgumentVariables(irg.getVariables(), irg.getNoArgs());
// x86cg.setSpilledVariables(lsa.getSpilledVariables());
// x86cg.emitHeader();
//
// n = quads.size();
// for (int i=0; i<n; i+=1) {
// Quad quad = (Quad) quads.get(i);
// if (!quad.isDeadCode()) {
// quad.generateCode(x86cg);
// }
// }
}
private static <T extends X86Register> void printCFG(IRControlFlowGraph<T> cfg, String x) {
System.out.println(x);
for (IRBasicBlock<T> b : cfg) {
System.out.println(b + ", stackOffset = " + b.getStackOffset());
for (Quad<T> q : b.getQuads()) {
if (!q.isDeadCode()) {
System.out.println(q);
}
}
}
System.out.println();
}
private static VmByteCode loadByteCode(String className, String methodName)
throws MalformedURLException, ClassNotFoundException, InstantiationException {
//VmSystemClassLoader vmc = new VmSystemClassLoader(new File(".").toURL(), new VmX86Architecture32());
VmX86Architecture32 arch = new VmX86Architecture32();
VmSystemClassLoader vmc = new VmSystemClassLoader(new URL[]{
new File("core/build/classes").toURL(),
new File("local/classlib").toURL()
}, arch);
new VmImpl("?", arch, vmc.getSharedStatics(), true, vmc, null);
VmType<?> type = vmc.loadClass(className, true);
VmMethod arithMethod = null;
int nMethods = type.getNoDeclaredMethods();
for (int i = 0; i < nMethods; i += 1) {
VmMethod method = type.getDeclaredMethod(i);
if (methodName.equals(method.getName())) {
arithMethod = method;
break;
}
}
VmByteCode code = arithMethod.getBytecode();
return code;
}
public static <T> void printQuadDetail(Quad<T> quad) {
System.out.print(quad.getBasicBlock());
System.out.print(" ");
Variable[] vars = quad.getBasicBlock().getVariables();
System.out.print("[");
for (Variable var : vars) {
System.out.print(var);
System.out.print(",");
}
System.out.print("] ");
if (quad.isDeadCode()) {
System.out.print("(dead) ");
}
}
}