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
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
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);
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);
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();
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);
}
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;
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)) {
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;
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;
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;
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;
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;
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);
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
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);
addiu(R+rs,signedImmediate);
setTmp(); // addr
- // FEATURE: DO the preMemRead(true) thing for the rest of the S* instructions
preMemRead(true);
pushTmp();
memRead(true);
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();
break;
}
case 42: { // SWL
- preMemWrite1();
-
addiu(R+rs,signedImmediate);
- mg.add(DUP);
- setTmp(); // addr
-
- preMemWrite2(true);
+ setTmp();
- preMemRead();
+ preMemRead(true);
pushTmp();
memRead(true);
memWrite();
break;
case 46: { // SWR
- preMemWrite1();
-
addiu(R+rs,signedImmediate);
- mg.add(DUP);
- setTmp(); // addr
-
- preMemWrite2(true);
+ setTmp();
- preMemRead();
+ preMemRead(true);
pushTmp();
memRead(true);
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];
}
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));
}
}
}
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));
}
}
}
"hi","lo","fcsr"
};
-
- private static String regField(int reg) { return regField[reg]; }
private int pushRegWZ(int reg) {
if(reg == R+0) {
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;
}
// 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)) {
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;
}
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);
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;
}
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);
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}));
return h;
}
+ private final int tmpVar = 1;
private void pushTmp() { mg.add(ILOAD_1); }
private void setTmp() { mg.add(ISTORE_1); }