diff --git a/ChangeLog b/ChangeLog index f781dc5..be071d8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +Sun Jun 7 03:02:35 2009 Minero Aoki + + * net/loveruby/cflat/sysdep/x86/CodeGenerator.java: refactoring + compileFunctionBody. + + * net/loveruby/cflat/sysdep/x86/AssemblyFile.java: objectify + VirtualStack. + + * net/loveruby/cflat/asm/IndirectMemoryReference.java: new method + .relocatable to generate relocatable IndirectMemoryReference. + + * net/loveruby/cflat/asm/MemoryReference.java: new method + #fixOffset. + + * net/loveruby/cflat/asm/DirectMemoryReference.java: new method + #fixOffset. + + * net/loveruby/cflat/asm/Assembly.java: remove fixStackOffset. + + * net/loveruby/cflat/asm/Operand.java: ditto. + Sat Jun 6 21:36:09 2009 Minero Aoki * lib/alloca.s: shorten assembly. diff --git a/net/loveruby/cflat/asm/Assembly.java b/net/loveruby/cflat/asm/Assembly.java index 0b14b4f..4c3f5e5 100644 --- a/net/loveruby/cflat/asm/Assembly.java +++ b/net/loveruby/cflat/asm/Assembly.java @@ -23,8 +23,4 @@ abstract public class Assembly { public void collectStatistics(Statistics stats) { // does nothing by default. } - - public void fixStackOffset(long diff) { - // does nothing by default. - } } diff --git a/net/loveruby/cflat/asm/DirectMemoryReference.java b/net/loveruby/cflat/asm/DirectMemoryReference.java index c8bc018..59d7e5d 100644 --- a/net/loveruby/cflat/asm/DirectMemoryReference.java +++ b/net/loveruby/cflat/asm/DirectMemoryReference.java @@ -15,6 +15,10 @@ public class DirectMemoryReference extends MemoryReference { value.collectStatistics(stats); } + public void fixOffset(long diff) { + throw new Error("DirectMemoryReference#fixOffset"); + } + public String toString() { return toSource(SymbolTable.dummy()); } diff --git a/net/loveruby/cflat/asm/IndirectMemoryReference.java b/net/loveruby/cflat/asm/IndirectMemoryReference.java index 0ee1509..694e37f 100644 --- a/net/loveruby/cflat/asm/IndirectMemoryReference.java +++ b/net/loveruby/cflat/asm/IndirectMemoryReference.java @@ -1,37 +1,39 @@ package net.loveruby.cflat.asm; public class IndirectMemoryReference extends MemoryReference { - protected Literal offset; - protected Register base; - protected boolean fixed; - - public IndirectMemoryReference(Register base) { - this.offset = new IntegerLiteral(0); - this.base = base; - this.fixed = false; - } + Literal offset; + Register base; + boolean fixed; public IndirectMemoryReference(long offset, Register base) { - this.offset = new IntegerLiteral(offset); - this.base = base; - this.fixed = true; + this(new IntegerLiteral(offset), base, true); } public IndirectMemoryReference(Symbol offset, Register base) { + this(offset, base, true); + } + + static public IndirectMemoryReference relocatable(long offset, Register base) { + return new IndirectMemoryReference(new IntegerLiteral(offset), base, false); + } + + private IndirectMemoryReference( + Literal offset, Register base, boolean fixed) { this.offset = offset; this.base = base; - this.fixed = true; + this.fixed = fixed; } public Literal offset() { return offset; } - public void fixOffset(long realOffset) { + public void fixOffset(long diff) { if (fixed) { throw new Error("must not happen: fixed = true"); } - this.offset = new IntegerLiteral(realOffset); + long curr = ((IntegerLiteral)offset).value; + this.offset = new IntegerLiteral(curr + diff); this.fixed = true; } @@ -43,10 +45,6 @@ public class IndirectMemoryReference extends MemoryReference { base.collectStatistics(stats); } - public void fixStackOffset(long diff) { - offset = offset.plus(diff); - } - public String toString() { return toSource(SymbolTable.dummy()); } @@ -73,6 +71,7 @@ public class IndirectMemoryReference extends MemoryReference { public String dump() { return "(IndirectMemoryReference " + + (fixed ? "" : "*") + offset.dump() + " " + base.dump() + ")"; } } diff --git a/net/loveruby/cflat/asm/Instruction.java b/net/loveruby/cflat/asm/Instruction.java index 3d57a3e..9bbb99a 100644 --- a/net/loveruby/cflat/asm/Instruction.java +++ b/net/loveruby/cflat/asm/Instruction.java @@ -88,13 +88,6 @@ public class Instruction extends Assembly { } } - public void fixStackOffset(long diff) { - if (!needRelocation) return; - for (int i = 0; i < operands.length; i++) { - operands[i].fixStackOffset(diff); - } - } - public String toSource(SymbolTable table) { StringBuffer buf = new StringBuffer(); buf.append("\t"); diff --git a/net/loveruby/cflat/asm/MemoryReference.java b/net/loveruby/cflat/asm/MemoryReference.java index 47cd10c..bb4c2a1 100644 --- a/net/loveruby/cflat/asm/MemoryReference.java +++ b/net/loveruby/cflat/asm/MemoryReference.java @@ -6,6 +6,7 @@ abstract public class MemoryReference return true; } + abstract public void fixOffset(long diff); abstract protected int cmp(DirectMemoryReference mem); abstract protected int cmp(IndirectMemoryReference mem); } diff --git a/net/loveruby/cflat/asm/Operand.java b/net/loveruby/cflat/asm/Operand.java index 43f695f..c421b26 100644 --- a/net/loveruby/cflat/asm/Operand.java +++ b/net/loveruby/cflat/asm/Operand.java @@ -22,8 +22,4 @@ abstract public class Operand implements OperandPattern { public boolean match(Operand operand) { return equals(operand); } - - public void fixStackOffset(long diff) { - // does nothing by default - } } diff --git a/net/loveruby/cflat/asm/Statistics.java b/net/loveruby/cflat/asm/Statistics.java index b30017a..30c0990 100644 --- a/net/loveruby/cflat/asm/Statistics.java +++ b/net/loveruby/cflat/asm/Statistics.java @@ -1,5 +1,8 @@ package net.loveruby.cflat.asm; -import java.util.*; +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; public class Statistics { protected Map registerUsage; diff --git a/net/loveruby/cflat/sysdep/x86/AssemblyFile.java b/net/loveruby/cflat/sysdep/x86/AssemblyFile.java index b663518..58aee09 100644 --- a/net/loveruby/cflat/sysdep/x86/AssemblyFile.java +++ b/net/loveruby/cflat/sysdep/x86/AssemblyFile.java @@ -6,12 +6,14 @@ import java.util.ArrayList; import java.io.PrintStream; public class AssemblyFile implements net.loveruby.cflat.sysdep.AssemblyFile { - private final List assemblies; final Type naturalType; final long stackWordSize; final SymbolTable labelSymbols; final boolean verbose; - private int commentIndentLevel; + final VirtualStack virtualStack = new VirtualStack(); + private List assemblies = new ArrayList(); + private int commentIndentLevel = 0; + private Statistics statistics; AssemblyFile(Type naturalType, long stackWordSize, SymbolTable labelSymbols, boolean verbose) { @@ -19,9 +21,6 @@ public class AssemblyFile implements net.loveruby.cflat.sysdep.AssemblyFile { this.stackWordSize = stackWordSize; this.labelSymbols = labelSymbols; this.verbose = verbose; - this.assemblies = new ArrayList(); - this.commentIndentLevel = 0; - initVirtualStack(); } List assemblies() { @@ -51,6 +50,21 @@ public class AssemblyFile implements net.loveruby.cflat.sysdep.AssemblyFile { } } + void apply(PeepholeOptimizer opt) { + assemblies = opt.optimize(assemblies); + } + + private Statistics statistics() { + if (statistics == null) { + statistics = Statistics.collect(assemblies); + } + return statistics; + } + + boolean doesUses(Register reg) { + return statistics().doesRegisterUsed(reg); + } + void comment(String str) { assemblies.add(new Comment(str, commentIndentLevel)); } @@ -71,6 +85,20 @@ public class AssemblyFile implements net.loveruby.cflat.sysdep.AssemblyFile { assemblies.add(label); } + void reduceLabels() { + Statistics stats = statistics(); + List result = new ArrayList(); + for (Assembly asm : assemblies) { + if (asm.isLabel() && ! stats.doesSymbolUsed((Label)asm)) { + ; + } + else { + result.add(asm); + } + } + assemblies = result; + } + protected void directive(String direc) { assemblies.add(new Directive(direc)); } @@ -210,62 +238,85 @@ public class AssemblyFile implements net.loveruby.cflat.sysdep.AssemblyFile { // Virtual Stack // - // #@@range/virtual_stack{ - private long stackPointer; - private long stackPointerMax; + // #@@range/VirtualStack_ctor{ + class VirtualStack { + private long offset; + private long max; + private List memrefs = + new ArrayList(); - void initVirtualStack() { - stackPointer = 0; - stackPointerMax = stackPointer; - } + VirtualStack() { + reset(); + } + + void reset() { + offset = 0; + max = 0; + memrefs.clear(); + } // #@@} - // #@@range/maxTmpBytes{ - long maxTmpBytes() { - return stackPointerMax; - } - // #@@} + // #@@range/maxSize{ + long maxSize() { + return max; + } + // #@@} - // #@@range/stackTop{ - IndirectMemoryReference stackTop() { - return new IndirectMemoryReference(-stackPointer, bp()); - } - // #@@} + // #@@range/extend{ + void extend(long len) { + offset += len; + max = Math.max(offset, max); + } + // #@@} - private Register bp() { - return new Register(RegisterClass.BP, naturalType); + // #@@range/rewindVirtualStack{ + void rewind(long len) { + offset -= len; + } + // #@@} + + // #@@range/top{ + IndirectMemoryReference top() { + IndirectMemoryReference mem = relocatableMem(-offset, bp()); + memrefs.add(mem); + return mem; + } + // #@@} + + private IndirectMemoryReference relocatableMem(long offset, Register base) { + return IndirectMemoryReference.relocatable(offset, base); + } + + private Register bp() { + return new Register(RegisterClass.BP, naturalType); + } + + // #@@range/fixOffset{ + void fixOffset(long diff) { + for (IndirectMemoryReference mem : memrefs) { + mem.fixOffset(diff); + } + } + // #@@} } // #@@range/virtualPush{ void virtualPush(Register reg) { if (verbose) { - comment("push " + reg.baseName() + " -> " + stackTop()); + comment("push " + reg.baseName() + " -> " + virtualStack.top()); } - extendVirtualStack(stackWordSize); - relocatableMov(reg, stackTop()); + virtualStack.extend(stackWordSize); + mov(reg, virtualStack.top()); } // #@@} // #@@range/virtualPop{ void virtualPop(Register reg) { if (verbose) { - comment("pop " + reg.baseName() + " <- " + stackTop()); + comment("pop " + reg.baseName() + " <- " + virtualStack.top()); } - relocatableMov(stackTop(), reg); - rewindVirtualStack(stackWordSize); - } - // #@@} - - // #@@range/extendVirtualStack{ - void extendVirtualStack(long len) { - stackPointer += len; - stackPointerMax = Math.max(stackPointerMax, stackPointer); - } - // #@@} - - // #@@range/rewindVirtualStack{ - void rewindVirtualStack(long len) { - stackPointer -= len; + mov(virtualStack.top(), reg); + virtualStack.rewind(stackWordSize); } // #@@} diff --git a/net/loveruby/cflat/sysdep/x86/CodeGenerator.java b/net/loveruby/cflat/sysdep/x86/CodeGenerator.java index f088771..4b23951 100644 --- a/net/loveruby/cflat/sysdep/x86/CodeGenerator.java +++ b/net/loveruby/cflat/sysdep/x86/CodeGenerator.java @@ -396,41 +396,40 @@ public class CodeGenerator private void compileFunctionBody( AssemblyFile file, DefinedFunction func) { locateParameters(func.parameters()); - locateLocalVariables(func.body().scope()); + long lvarsSize = locateLocalVariables(func.body().scope(), 0); - AssemblyFile body = compileStmts(func); - List bodyAsms = optimize(body.assemblies()); - Statistics stats = Statistics.collect(bodyAsms); - bodyAsms = reduceLabels(bodyAsms, stats); - List saveRegs = usedCalleeSavedRegistersWithoutBP(stats); - long saveRegsBytes = stackSizeFromWordNum(saveRegs.size()); - long lvarBytes = fixLocalVariableOffsets( - func.body().scope(), saveRegsBytes); - fixTmpOffsets(bodyAsms, saveRegsBytes + lvarBytes); + AssemblyFile body = optimize(compileStmts(func)); + List saveRegs = usedCalleeSavedRegisters(body); + long saveRegsSize = stackSizeFromWordNum(saveRegs.size()); + fixLocalVariableOffsets(func.body().scope(), saveRegsSize); + body.virtualStack.fixOffset(saveRegsSize + lvarsSize); if (options.isVerboseAsm()) { - printStackFrameLayout(file, saveRegsBytes, lvarBytes, - body.maxTmpBytes(), func.localVariables()); + printStackFrameLayout(file, saveRegsSize, lvarsSize, + body.virtualStack.maxSize(), func.localVariables()); } - file.initVirtualStack(); + file.virtualStack.reset(); prologue(file, func, saveRegs, - saveRegsBytes + lvarBytes + body.maxTmpBytes()); + saveRegsSize + lvarsSize + body.virtualStack.maxSize()); if (options.isPositionIndependent() - && stats.doesRegisterUsed(GOTBaseReg())) { + && body.doesUses(GOTBaseReg())) { loadGOTBaseAddress(file, GOTBaseReg()); } - file.addAll(bodyAsms); - epilogue(file, func, saveRegs, lvarBytes); + file.addAll(body.assemblies()); + epilogue(file, func, saveRegs, lvarsSize); + file.virtualStack.fixOffset(0); } // #@@} // #@@range/optimize{ - private List optimize(List asms) { + private AssemblyFile optimize(AssemblyFile body) { if (options.optimizeLevel() < 1) { - return asms; + return body; } - return PeepholeOptimizer.defaultSet().optimize(asms); + body.apply(PeepholeOptimizer.defaultSet()); + body.reduceLabels(); + return body; } // #@@} @@ -490,41 +489,31 @@ public class CodeGenerator } // #@@} - // #@@range/reduceLabels{ - private List reduceLabels( - List assemblies, Statistics stats) { - List result = new ArrayList(); - for (Assembly asm : assemblies) { - if (asm.isLabel() && ! stats.doesSymbolUsed((Label)asm)) { - ; - } - else { - result.add(asm); - } - } - return result; - } - // #@@} - - private List usedCalleeSavedRegistersWithoutBP(Statistics stats) { + // does NOT include BP + private List usedCalleeSavedRegisters(AssemblyFile asm) { List result = new ArrayList(); for (Register reg : calleeSavedRegisters()) { - if (stats.doesRegisterUsed(reg) && !reg.equals(bp())) { + if (asm.doesUses(reg)) { result.add(reg); } } + result.remove(bp()); return result; } + static final RegisterClass[] CALLEE_SAVED_REGISTERS = { + RegisterClass.BX, RegisterClass.BP, + RegisterClass.SI, RegisterClass.DI + }; + private List calleeSavedRegistersCache = null; private List calleeSavedRegisters() { if (calleeSavedRegistersCache == null) { List regs = new ArrayList(); - regs.add(bx()); - regs.add(si()); - regs.add(di()); - regs.add(bp()); + for (RegisterClass c : CALLEE_SAVED_REGISTERS) { + regs.add(new Register(c, naturalType)); + } calleeSavedRegistersCache = regs; } return calleeSavedRegistersCache; @@ -586,45 +575,31 @@ public class CodeGenerator * not determined, assign unfixed IndirectMemoryReference. */ // #@@range/locateLocalVariables{ - private void locateLocalVariables(LocalScope scope) { - for (DefinedVariable var : scope.allLocalVariables()) { - var.setMemref(new IndirectMemoryReference(bp())); - } - } - // #@@} - - /** - * Fixes addresses of local variables. - * Returns byte-length of the local variable area. - */ - // #@@range/fixLocalVariableOffsets{ - private long fixLocalVariableOffsets(LocalScope scope, long initLen) { - long maxLen = allocateScope(scope, initLen); - return maxLen - initLen; - } - // #@@} - - // #@@range/allocateScope{ - private long allocateScope(LocalScope scope, long parentStackLen) { + private long locateLocalVariables( + LocalScope scope, long parentStackLen) { long len = parentStackLen; for (DefinedVariable var : scope.localVariables()) { len = alignStack(len + var.allocSize()); - fixMemref((IndirectMemoryReference)var.memref(), -len); + var.setMemref(relocatableMem(-len, bp())); } - // Allocate local variables in child scopes. - // We allocate child scopes in the same area (overrapped). long maxLen = len; for (LocalScope s : scope.children()) { - long childLen = allocateScope(s, len); + long childLen = locateLocalVariables(s, len); maxLen = Math.max(maxLen, childLen); } return maxLen; } // #@@} - // #@@range/fixMemref{ - private void fixMemref(IndirectMemoryReference memref, long offset) { - memref.fixOffset(offset); + private IndirectMemoryReference relocatableMem(long offset, Register base) { + return IndirectMemoryReference.relocatable(offset, base); + } + + // #@@range/fixLocalVariableOffsets{ + private void fixLocalVariableOffsets(LocalScope scope, long len) { + for (DefinedVariable var : scope.allLocalVariables()) { + var.memref().fixOffset(-len); + } } // #@@} @@ -644,14 +619,6 @@ public class CodeGenerator } // #@@} - // #@@range/fixTmpOffsets{ - private void fixTmpOffsets(List asms, long offset) { - for (Assembly asm : asms) { - asm.fixStackOffset(-offset); - } - } - // #@@} - /** * Implements cdecl function call: * * All arguments are on stack.