single-float
[nestedvm.git] / src / org / ibex / nestedvm / ClassFileCompiler.java
index 0cb9888..aa99aa3 100644 (file)
@@ -5,9 +5,7 @@ import java.io.*;
 import org.ibex.nestedvm.util.*;
 import org.ibex.classgen.*;
 
-// FEATURE: Use IINC where possible
-// FEATURE: Some kind of peephole optimization
-// FEATURE: Special mode to support single-precision only - regs are floats not ints
+// FEATURE: Eliminate unnecessary use of SWAP
 
 /* FEATURE: Span large binaries across several classfiles
  * We should be able to do this with no performance penalty
@@ -53,7 +51,15 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
     public void setWarnWriter(PrintStream warn) { this.warn = warn; }
         
     protected void _go() throws Exn, IOException {
-        if(lessConstants) throw new Exn("ClassFileCompiler doesn't support -o lessconstants");
+        try {
+            __go();
+        } catch(ClassGen.Exn e) {
+            e.printStackTrace(warn);
+            throw new Exn("Class generation exception: " + e.toString());
+        }
+    }
+    
+    private void __go() throws Exn, IOException {
         if(!pruneCases) throw new Exn("-o prunecases MUST be enabled for ClassFileCompiler");
 
         // Class
@@ -68,7 +74,7 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         cg.addField("lo",Type.INT,ACC_PRIVATE);
         cg.addField("fcsr",Type.INT,ACC_PRIVATE);
         for(int i=1;i<32;i++) cg.addField("r" + i,Type.INT,ACC_PRIVATE);
-        for(int i=0;i<32;i++) cg.addField("f" + i,Type.INT,ACC_PRIVATE);
+        for(int i=0;i<32;i++) cg.addField("f" + i,singleFloat ? Type.FLOAT : Type.INT,ACC_PRIVATE);
         
         clinit = cg.addMethod("<clinit>",Type.VOID,Type.NO_ARGS,ACC_PRIVATE|ACC_STATIC);
         
@@ -156,7 +162,8 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         int start = tramp.size();
         tramp.add(ALOAD_0);
         tramp.add(GETFIELD,new FieldRef(me,"state",Type.INT));
-        int stateCheck = tramp.add(IFNE);
+        tramp.add(IFEQ,tramp.size()+2);
+        tramp.add(RETURN);
         
         tramp.add(ALOAD_0);
         tramp.add(ALOAD_0);
@@ -196,9 +203,6 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"toString",Type.STRING,Type.NO_ARGS));
         tramp.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"<init>",Type.VOID,new Type[]{Type.STRING}));
         tramp.add(ATHROW);
-        
-        tramp.setArg(stateCheck,tramp.size());
-        tramp.add(RETURN);
                 
         try {
             tramp.finish();
@@ -270,12 +274,14 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             setCPUState.add(ALOAD_2);
             setCPUState.add(LDC,i);
             setCPUState.add(IALOAD);
-            setCPUState.add(PUTFIELD,new FieldRef(me,"f"+i,Type.INT));
+            if(singleFloat) setCPUState.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"intBitsToFloat",Type.FLOAT,new Type[]{Type.INT}));
+            setCPUState.add(PUTFIELD,new FieldRef(me,"f"+i,singleFloat ? Type.FLOAT : Type.INT));
             
             getCPUState.add(ALOAD_2);
             getCPUState.add(LDC,i);
             getCPUState.add(ALOAD_0);
-            getCPUState.add(GETFIELD,new FieldRef(me,"f"+i,Type.INT));
+            getCPUState.add(GETFIELD,new FieldRef(me,"f"+i,singleFloat ? Type.FLOAT: Type.INT));
+            if(singleFloat) getCPUState.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"floatToIntBits",Type.INT,new Type[]{Type.FLOAT}));
             getCPUState.add(IASTORE);            
         }
         
@@ -418,7 +424,13 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
                 continue;
             }
             try {
+                int o = preSetRegStackPos;
                 skipNext = emitInstruction(addr,insn,nextInsn);
+                if(o != preSetRegStackPos) throw new Exn("here");
+            } catch(Exn e) {
+                e.printStackTrace(warn);
+                warn.println("Exception at " + toHex(addr));
+                throw e;                
             } catch(RuntimeException e) {
                 warn.println("Exception at " + toHex(addr));
                 throw e;
@@ -521,6 +533,21 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
     private void leaveMethod() {
         mg.add(GOTO,returnTarget);
     }
+    
+    private void link(int mypc) {
+        preSetReg(R+RA);
+        if(lessConstants){
+            int ref = (mypc+8 + 32768) & ~65535;
+            int diff = (mypc+8) - ref;
+            if(diff < -32768 || diff > 32767) throw new Error("should never happen " + diff);
+            mg.add(LDC,ref);
+            mg.add(LDC,diff);
+            mg.add(IADD);
+        } else {
+            mg.add(LDC,mypc+8);
+        }
+        setReg();
+    }
 
     private void branch(int pc, int target) {
         if((pc&methodMask) == (target&methodMask)) {
@@ -584,12 +611,12 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         int fd = (insn >>> 6) & 0x1f;
         int subcode = insn & 0x3f;                     // bits 0-5 
         int breakCode = (insn >>> 6) & 0xfffff;         // bits 6-20
-
+    
         int jumpTarget = (insn & 0x03ffffff);          // bits 0-25
         int unsignedImmediate = insn & 0xffff;
         int signedImmediate = (insn << 16) >> 16;
         int branchTarget = signedImmediate;
-
+    
         // temporaries
         int b1,b2;
         
@@ -651,13 +678,10 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             case 9: // JALR
                 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
                 emitInstruction(-1,nextInsn,-1);
+                link(pc);
                 preSetPC();
                 pushRegWZ(R+rs);
                 setPC();
-                
-                preSetReg(R+RA);
-                mg.add(LDC,pc+8);
-                setReg();
                 leaveMethod();
                 unreachable = true;
                 break;
@@ -948,9 +972,7 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
                 pushRegWZ(R+rs);
                 b1 = mg.add(IFGE);
                 emitInstruction(-1,nextInsn,-1);
-                preSetReg(R+RA);
-                mg.add(LDC,pc+8);
-                setReg();
+                link(pc);
                 branch(pc,pc+branchTarget*4+4);
                 mg.setArg(b1,mg.size());
                 break;
@@ -962,9 +984,7 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
                     b1 = mg.add(IFLT);
                 }
                 emitInstruction(-1,nextInsn,-1);
-                preSetReg(R+RA);
-                mg.add(LDC,pc+8);
-                setReg();
+                link(pc);
                 branch(pc,pc+branchTarget*4+4);
                 if(b1 != -1) mg.setArg(b1,mg.size());
                 if(b1 == -1) unreachable = true;
@@ -985,9 +1005,7 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             if(pc == -1) throw new Exn("pc modifying insn in delay slot");
             int target = (pc&0xf0000000)|(jumpTarget << 2);
             emitInstruction(-1,nextInsn,-1);
-            preSetReg(R+RA);
-            mg.add(LDC,pc+8);
-            setReg();
+            link(pc);
             branch(pc, target);
             unreachable = true;
             break;
@@ -1027,9 +1045,16 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         case 8: // ADDI
             throw new Exn("ADDI (add immediate with oveflow trap) not suported");
         case 9: // ADDIU
-            preSetReg(R+rt);
-            addiu(rs,signedImmediate);
-            setReg();            
+            if(rs != 0 && signedImmediate != 0 && rs == rt && doLocal(rt) && signedImmediate >= -32768 && signedImmediate <= 32767) {
+                // HACK: This should be a little cleaner
+                regLocalReadCount[rt]++;
+                regLocalWriteCount[rt]++;
+                mg.add(IINC, new MethodGen.Pair(getLocalForReg(rt),signedImmediate));
+            } else {
+                preSetReg(R+rt);
+                addiu(rs,signedImmediate);
+                setReg();
+            }
             break;
         case 10: // SLTI
             preSetReg(R+rt);
@@ -1108,10 +1133,8 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
                 break;
             case 4: // MTC.1
                 preSetReg(F+rd);
-                if(rt != 0)
-                    pushReg(R+rt);
-                else
-                    mg.add(LDC,0);
+                if(rt != 0) pushReg(R+rt);
+                else mg.add(ICONST_0);
                 setReg();
                 break;
             case 6: // CTC.1
@@ -1186,13 +1209,12 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
                     preSetReg(F+fd);
                     pushReg(F+fs);
                     setReg();
-                    
+                
                     if(d) {
                         preSetReg(F+fd+1);
                         pushReg(F+fs+1);
                         setReg();
                     }
-                    
                     break;
                 case 7: // NEG.X
                     preSetDouble(F+fd,d);
@@ -1460,7 +1482,6 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             addiu(R+rs,signedImmediate);
             setTmp(); // addr
             
-            // FEATURE: DO the preMemRead(true) thing for the rest of the S* instructions
             preMemRead(true);
             pushTmp();
             memRead(true);
@@ -1500,19 +1521,13 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             break;
         }
         case 41: { // SH    
-            preMemWrite1();
-            
             addiu(R+rs,signedImmediate);
+            setTmp();
             
-            mg.add(DUP);
-            setTmp(); // addr
-            
-            preMemWrite2(true);
-            
-            preMemRead();
+            preMemRead(true);
             pushTmp();
             memRead(true);
-            
+                       
             mg.add(LDC,0xffff);
             pushTmp();
             
@@ -1546,15 +1561,10 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             break;            
         }
         case 42: { // SWL
-            preMemWrite1();
-            
             addiu(R+rs,signedImmediate);
-            mg.add(DUP);
-            setTmp(); // addr
-
-            preMemWrite2(true);
+            setTmp();
             
-            preMemRead();
+            preMemRead(true);            
             pushTmp();
             memRead(true);
             
@@ -1591,15 +1601,10 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             memWrite();
             break;
         case 46: { // SWR
-            preMemWrite1();
-            
             addiu(R+rs,signedImmediate);
-            mg.add(DUP);
-            setTmp(); // addr
-            
-            preMemWrite2(true);
+            setTmp();
             
-            preMemRead();
+            preMemRead(true);
             pushTmp();
             memRead(true);
             
@@ -1689,7 +1694,7 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
     
     private int getLocalForReg(int reg) {
         if(regLocalMapping[reg] != 0) return regLocalMapping[reg];
-        if(nextAvailLocal == 0) nextAvailLocal = onePage ? 3 : 4;
+        if(nextAvailLocal == 0) nextAvailLocal = onePage ? 4 : 5;
         regLocalMapping[reg] = nextAvailLocal++;
         return regLocalMapping[reg];
     }
@@ -1708,13 +1713,13 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         for(int i=0;i<REG_COUNT;i++) {
             if(regLocalMapping[i] == 0) continue;
             mg.set(p++,ALOAD_0);
-            mg.set(p++,GETFIELD,new FieldRef(me,regField(i),Type.INT));
+            mg.set(p++,GETFIELD,new FieldRef(me,regField[i],Type.INT));
             mg.set(p++,ISTORE,regLocalMapping[i]);
             
             if(regLocalWriteCount[i] > 0) {
                 mg.add(ALOAD_0);
                 mg.add(ILOAD,regLocalMapping[i]);
-                mg.add(PUTFIELD,new FieldRef(me,regField(i),Type.INT));
+                mg.add(PUTFIELD,new FieldRef(me,regField[i],Type.INT));
             }
         }
     }
@@ -1724,7 +1729,7 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             if(regLocalWriteCount[i] > 0) {
                 mg.add(ALOAD_0);
                 mg.add(ILOAD,regLocalMapping[i]);
-                mg.add(PUTFIELD,new FieldRef(me,regField(i),Type.INT));
+                mg.add(PUTFIELD,new FieldRef(me,regField[i],Type.INT));
             }
         }
     }
@@ -1742,8 +1747,6 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             
             "hi","lo","fcsr"
     };
-    
-    private static String regField(int reg) { return regField[reg]; }
         
     private int pushRegWZ(int reg) {
         if(reg == R+0) {
@@ -1764,10 +1767,13 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         if(doLocal(reg)) {
             regLocalReadCount[reg]++;
             mg.add(ILOAD,getLocalForReg(reg));
-            
+        } else if(reg >= F+0 && reg <= F+31 && singleFloat) {
+            mg.add(ALOAD_0);
+            mg.add(GETFIELD,new FieldRef(me,regField[reg],Type.FLOAT));
+            mg.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"floatToIntBits",Type.INT,new Type[]{Type.FLOAT}));
         } else {
             mg.add(ALOAD_0);
-            mg.add(GETFIELD,new FieldRef(me,regField(reg),Type.INT));
+            mg.add(GETFIELD,new FieldRef(me,regField[reg],Type.INT));
         }
         return h;
     }
@@ -1777,7 +1783,6 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
     
     // This can push ONE or ZERO words to the stack. If it pushed one it returns true
     private boolean preSetReg(int reg) {
-        regField(reg); // just to check for validity
         preSetRegStack[preSetRegStackPos] = reg;
         preSetRegStackPos++;
         if(doLocal(reg)) {
@@ -1796,8 +1801,11 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         if(doLocal(reg)) {
             mg.add(ISTORE,getLocalForReg(reg));
             regLocalWriteCount[reg]++;
+        } else if(reg >= F+0 && reg <= F+31 && singleFloat) {
+            mg.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"intBitsToFloat",Type.FLOAT,new Type[]{Type.INT}));
+            mg.add(PUTFIELD,new FieldRef(me,regField[reg],Type.FLOAT));            
         } else {
-            mg.add(PUTFIELD,new FieldRef(me,regField(reg),Type.INT));
+            mg.add(PUTFIELD,new FieldRef(me,regField[reg],Type.INT));
         }
         return h;
     }
@@ -1807,12 +1815,13 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         return mg.add(PUTFIELD,new FieldRef(me,"pc",Type.INT));
     }
     
-    //unused - private InstructionHandle pushFloat(int reg) throws CompilationException { return pushDouble(reg,false); }
     //unused - private InstructionHandle pushDouble(int reg) throws CompilationException { return pushDouble(reg,true); }
+    private int pushFloat(int reg) throws Exn { return pushDouble(reg,false); }
     private int pushDouble(int reg, boolean d) throws Exn {
         if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg);
         int h = mg.size();
         if(d) {
+            if(singleFloat) throw new Exn("Double operations not supported when singleFloat is enabled");
             if(reg == F+31) throw new Exn("Tried to use a double in f31");
             pushReg(reg+1);
             mg.add(I2L);
@@ -1824,9 +1833,12 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             mg.add(LAND);
             mg.add(LOR);
             mg.add(INVOKESTATIC,new MethodRef(Type.DOUBLE_OBJECT,"longBitsToDouble",Type.DOUBLE,new Type[]{Type.LONG}));
+        } else if(singleFloat) {
+            mg.add(ALOAD_0);
+            mg.add(GETFIELD,new FieldRef(me,regField[reg],Type.FLOAT));
         } else {
             pushReg(reg);
-            mg.add(INVOKESTATIC,new MethodRef("java.lang.Float","intToFloatBits",Type.FLOAT,new Type[]{Type.INT}));
+            mg.add(INVOKESTATIC,new MethodRef("java.lang.Float","intBitsToFloat",Type.FLOAT,new Type[]{Type.INT}));
         }
         return h;
     }
@@ -1842,6 +1854,7 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg);
         int h = mg.size();
         if(d) {
+            if(singleFloat) throw new Exn("Double operations not supported when singleFloat is enabled");
             if(reg == F+31) throw new Exn("Tried to use a double in f31");
             mg.add(INVOKESTATIC,new MethodRef(Type.DOUBLE_OBJECT,"doubleToLongBits",Type.LONG,new Type[]{Type.DOUBLE}));
             mg.add(DUP2);
@@ -1853,6 +1866,10 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             setReg();
             mg.add(L2I);
             setReg(); // preSetReg was already done for this by preSetDouble
+        } else if(singleFloat) {
+            // HACK: Clean this up
+            preSetRegStackPos--;
+            mg.add(PUTFIELD,new FieldRef(me,regField[reg],Type.FLOAT));
         } else {
             //h = a(fac.createInvoke("java.lang.Float","floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT},INVOKESTATIC));
             mg.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT}));
@@ -1861,6 +1878,7 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         return h;
     }
     
+    private final int tmpVar = 1;
     private void pushTmp() { mg.add(ILOAD_1); }
     private void setTmp() { mg.add(ISTORE_1); }