diff --git a/ChangeLog b/ChangeLog index fbf8f68..d679953 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +Sun Dec 7 22:27:51 2008 Minero Aoki + + * net/loveruby/cflat/compiler/CodeGenerator.java: manage stack + offset by generator, instead of using machine push/pop. + + * net/loveruby/cflat/asm/Assembler.java: new method + relocatableMov. + + * net/loveruby/cflat/asm/Assembly.java: allow fixing indirect + memory access offset. + + * net/loveruby/cflat/asm/Instruction.java: ditto. + + * net/loveruby/cflat/asm/AsmOperand.java: ditto. + + * net/loveruby/cflat/asm/IndirectMemoryReference.java: ditto. + + * net/loveruby/cflat/asm/IntegerLiteral.java: ditto. + + * net/loveruby/cflat/asm/Literal.java: ditto. + + * net/loveruby/cflat/asm/BaseSymbol.java: ditto. + + * net/loveruby/cflat/asm/SuffixedSymbol.java: ditto. + Sun Dec 7 17:13:45 2008 Minero Aoki * net/loveruby/cflat/compiler/LocalReferenceResolver.java -> diff --git a/net/loveruby/cflat/asm/AsmOperand.java b/net/loveruby/cflat/asm/AsmOperand.java index 6d374d4..a21afc7 100644 --- a/net/loveruby/cflat/asm/AsmOperand.java +++ b/net/loveruby/cflat/asm/AsmOperand.java @@ -21,4 +21,8 @@ abstract public class AsmOperand implements OperandPattern { public boolean match(AsmOperand operand) { return equals(operand); } + + public void fixStackOffset(long diff) { + // does nothing by default + } } diff --git a/net/loveruby/cflat/asm/Assembler.java b/net/loveruby/cflat/asm/Assembler.java index 339732c..9ee5b8a 100644 --- a/net/loveruby/cflat/asm/Assembler.java +++ b/net/loveruby/cflat/asm/Assembler.java @@ -275,6 +275,11 @@ public class Assembler { mov(naturalType, src, dest); } + // for stack access + public void relocatableMov(AsmOperand src, AsmOperand dest) { + assemblies.add(new Instruction("mov", typeSuffix(naturalType), src, dest, true)); + } + public void mov(Type type, AsmOperand src, AsmOperand dest) { insn(type, "mov", src, dest); } diff --git a/net/loveruby/cflat/asm/Assembly.java b/net/loveruby/cflat/asm/Assembly.java index ee5986e..1f0d5dd 100644 --- a/net/loveruby/cflat/asm/Assembly.java +++ b/net/loveruby/cflat/asm/Assembly.java @@ -22,4 +22,8 @@ abstract public class Assembly { public void collectStatistics(AsmStatistics stats) { // does nothing by default. } + + public void fixStackOffset(long diff) { + // does nothing by default. + } } diff --git a/net/loveruby/cflat/asm/BaseSymbol.java b/net/loveruby/cflat/asm/BaseSymbol.java index ce53853..8b11c2f 100644 --- a/net/loveruby/cflat/asm/BaseSymbol.java +++ b/net/loveruby/cflat/asm/BaseSymbol.java @@ -8,4 +8,8 @@ abstract public class BaseSymbol implements Symbol { public void collectStatistics(AsmStatistics stats) { stats.symbolUsed(this); } + + public Literal plus(long n) { + throw new Error("must not happen: BaseSymbol.plus called"); + } } diff --git a/net/loveruby/cflat/asm/IndirectMemoryReference.java b/net/loveruby/cflat/asm/IndirectMemoryReference.java index 2283557..b65907a 100644 --- a/net/loveruby/cflat/asm/IndirectMemoryReference.java +++ b/net/loveruby/cflat/asm/IndirectMemoryReference.java @@ -43,6 +43,10 @@ public class IndirectMemoryReference extends MemoryReference { base.collectStatistics(stats); } + public void fixStackOffset(long diff) { + offset = offset.plus(diff); + } + public String toString() { return toSource(SymbolTable.dummy()); } diff --git a/net/loveruby/cflat/asm/Instruction.java b/net/loveruby/cflat/asm/Instruction.java index ff244dd..7a1f42e 100644 --- a/net/loveruby/cflat/asm/Instruction.java +++ b/net/loveruby/cflat/asm/Instruction.java @@ -5,32 +5,41 @@ public class Instruction extends Assembly { protected String mnemonic; protected String suffix; protected AsmOperand[] operands; + protected boolean needRelocation; public Instruction(String mnemonic) { - this(mnemonic, "", new AsmOperand[0]); + this(mnemonic, "", new AsmOperand[0], false); } public Instruction(String mnemonic, String suffix, AsmOperand a1) { - this(mnemonic, suffix, new AsmOperand[] { a1 }); + this(mnemonic, suffix, new AsmOperand[] { a1 }, false); } public Instruction(String mnemonic, String suffix, AsmOperand a1, AsmOperand a2) { - this(mnemonic, suffix, new AsmOperand[] { a1, a2 }); + this(mnemonic, suffix, new AsmOperand[] { a1, a2 }, false); } - public Instruction(String mnemonic, String suffix, AsmOperand[] operands) { + public Instruction(String mnemonic, String suffix, + AsmOperand a1, AsmOperand a2, boolean reloc) { + this(mnemonic, suffix, new AsmOperand[] { a1, a2 }, reloc); + } + + public Instruction(String mnemonic, String suffix, AsmOperand[] operands, boolean reloc) { this.mnemonic = mnemonic; this.suffix = suffix; this.operands = operands; + this.needRelocation = reloc; } public Instruction build(String mnemonic, AsmOperand o1) { - return new Instruction(mnemonic, this.suffix, new AsmOperand[] { o1 }); + return new Instruction(mnemonic, this.suffix, + new AsmOperand[] { o1 }, needRelocation); } public Instruction build(String mnemonic, AsmOperand o1, AsmOperand o2) { - return new Instruction(mnemonic, this.suffix, new AsmOperand[] { o1, o2 }); + return new Instruction(mnemonic, this.suffix, + new AsmOperand[] { o1, o2 }, needRelocation); } public boolean isInstruction() { @@ -79,6 +88,13 @@ 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/IntegerLiteral.java b/net/loveruby/cflat/asm/IntegerLiteral.java index f9e3149..5c8603e 100644 --- a/net/loveruby/cflat/asm/IntegerLiteral.java +++ b/net/loveruby/cflat/asm/IntegerLiteral.java @@ -24,6 +24,10 @@ public class IntegerLiteral implements Literal { return value == 0; } + public IntegerLiteral plus(long diff) { + return new IntegerLiteral(value + diff); + } + public IntegerLiteral integerLiteral() { return this; } @@ -39,4 +43,8 @@ public class IntegerLiteral implements Literal { public void collectStatistics(AsmStatistics stats) { // does nothing } + + public String toString() { + return "$" + value; + } } diff --git a/net/loveruby/cflat/asm/Literal.java b/net/loveruby/cflat/asm/Literal.java index 95836fe..966be81 100644 --- a/net/loveruby/cflat/asm/Literal.java +++ b/net/loveruby/cflat/asm/Literal.java @@ -5,4 +5,5 @@ public interface Literal { public String toSource(SymbolTable table); public void collectStatistics(AsmStatistics stats); public boolean isZero(); + public Literal plus(long diff); } diff --git a/net/loveruby/cflat/asm/SuffixedSymbol.java b/net/loveruby/cflat/asm/SuffixedSymbol.java index a288beb..e98c819 100644 --- a/net/loveruby/cflat/asm/SuffixedSymbol.java +++ b/net/loveruby/cflat/asm/SuffixedSymbol.java @@ -17,6 +17,10 @@ public class SuffixedSymbol implements Symbol { base.collectStatistics(stats); } + public Literal plus(long n) { + throw new Error("must not happen: SuffixedSymbol.plus called"); + } + public String name() { return base.name(); } diff --git a/net/loveruby/cflat/compiler/CodeGenerator.java b/net/loveruby/cflat/compiler/CodeGenerator.java index 4208604..efcc78e 100644 --- a/net/loveruby/cflat/compiler/CodeGenerator.java +++ b/net/loveruby/cflat/compiler/CodeGenerator.java @@ -304,13 +304,15 @@ public class CodeGenerator // #@@} protected void compileFunctionBody(DefinedFunction func) { + initStackParams(); List bodyAsms = compileStmts(func); AsmStatistics stats = AsmStatistics.collect(bodyAsms); bodyAsms = reduceLabels(bodyAsms, stats); List saveRegs = usedCalleeSavedRegisters(stats); - long lvarBytes = allocateLocalVariables(func.body().scope(), - saveRegs.size()); - prologue(func, saveRegs, lvarBytes); + long lvarBytes = allocateLocalVariables(func.body().scope(), savedRegsSize(saveRegs)); + fixStackOffsets(bodyAsms, savedRegsSize(saveRegs) + lvarBytes); + + prologue(func, saveRegs, savedRegsSize(saveRegs) + lvarBytes + maxStackLength()); if (options.isPositionIndependent() && stats.doesRegisterUsed(GOTBaseReg())) { loadGOTBaseAddress(GOTBaseReg()); } @@ -318,6 +320,16 @@ public class CodeGenerator epilogue(func, saveRegs, lvarBytes); } + protected long savedRegsSize(List regs) { + long numReallySaved = 0; + for (Register reg : regs) { + if (! reg.baseName().equals("bp")) { + numReallySaved++; + } + } + return numReallySaved * stackWordSize; + } + protected List compileStmts(DefinedFunction func) { pushAssembler(); currentFunction = func; @@ -418,11 +430,11 @@ public class CodeGenerator // #@@range/prologue{ protected void prologue(DefinedFunction func, List saveRegs, - long lvarBytes) { - push(bp()); + long frameSize) { + truePush(bp()); mov(sp(), bp()); saveRegisters(saveRegs); - extendStack(lvarBytes); + allocateStack(frameSize); if (options.isVerboseAsm()) { for (DefinedVariable var : func.localVariables()) { comment("mem " + var.memref() + ": " + var.name()); @@ -435,10 +447,10 @@ public class CodeGenerator protected void epilogue(DefinedFunction func, List savedRegs, long lvarBytes) { - shrinkStack(lvarBytes); + //shrinkStack(lvarBytes); restoreRegisters(savedRegs); mov(bp(), sp()); - pop(bp()); + truePop(bp()); ret(); } // #@@} @@ -489,10 +501,9 @@ public class CodeGenerator * Returns byte-length of the local variable area. * Note that numSavedRegs includes bp. */ - protected long allocateLocalVariables(LocalScope scope, long numSavedRegs) { - long initLen = (numSavedRegs - 1) * stackWordSize; - long maxLen = allocateScope(scope, initLen); - return maxLen - initLen; + protected long allocateLocalVariables(LocalScope scope, long offset) { + long maxLen = allocateScope(scope, offset); + return maxLen - offset; } protected long allocateScope(LocalScope scope, long parentStackLen) { @@ -521,15 +532,60 @@ public class CodeGenerator memref.fixOffset(offset); } - protected void extendStack(long len) { + protected void allocateStack(long len) { if (len > 0) { - add(imm(len * (stackGrowsLower ? -1 : 1)), sp()); + if (stackGrowsLower) { + sub(imm(len), sp()); + } + else { + add(imm(len), sp()); + } } } - protected void shrinkStack(long len) { - if (len > 0) { - add(imm(len * (stackGrowsLower ? 1 : -1)), sp()); + protected long stackPointer; + protected long stackPointerMax; + + protected void initStackParams() { + stackPointer = 0; + stackPointerMax = stackPointer; + } + + protected long maxStackLength() { + return stackPointerMax; + } + + protected IndirectMemoryReference stackTop() { + if (stackGrowsLower) { + return mem(-stackPointer, bp()); + } + else { + return mem(stackPointer - stackWordSize, bp()); + } + } + + protected void push(Register reg) { + extendStack(stackWordSize); + as.relocatableMov(reg, stackTop()); + } + + protected void pop(Register reg) { + as.relocatableMov(stackTop(), reg); + rewindStack(stackWordSize); + } + + protected void extendStack(long len) { + stackPointer += len; + stackPointerMax = Math.max(stackPointerMax, stackPointer); + } + + protected void rewindStack(long len) { + stackPointer -= len; + } + + protected void fixStackOffsets(List asms, long offset) { + for (Assembly asm : asms) { + asm.fixStackOffset(offset * (stackGrowsLower ? -1 : 1)); } } @@ -541,9 +597,12 @@ public class CodeGenerator public void visit(FuncallNode node) { // compile function arguments from right to left. ListIterator args = node.finalArg(); + long argIndex = node.numArgs() - 1; while (args.hasPrevious()) { compile(args.previous()); - push(reg("ax")); + mov(reg("ax"), argMemory(argIndex)); + argIndex--; + extendStack(stackWordSize); } // call if (node.isStaticCall()) { @@ -557,7 +616,16 @@ public class CodeGenerator } // rewind stack // >4 bytes arguments are not supported. - shrinkStack(node.numArgs() * stackWordSize); + rewindStack(node.numArgs() * stackWordSize); + } + + protected IndirectMemoryReference argMemory(long argIndex) { + if (stackGrowsLower) { + return mem(stackWordSize * argIndex, sp()); + } + else { + return mem(-stackWordSize * (argIndex + 1), sp()); + } } public void visit(ReturnNode node) { @@ -1248,8 +1316,8 @@ public class CodeGenerator public void setl(Register reg) { as.setl(reg); } public void setle(Register reg) { as.setle(reg); } public void test(Type type, Register a, Register b) { as.test(type, a, b); } - public void push(Register reg) { as.push(reg); } - public void pop(Register reg) { as.pop(reg); } + protected void truePush(Register reg) { as.push(reg); } + protected void truePop(Register reg) { as.pop(reg); } public void call(Symbol sym) { as.call(sym); } public void callAbsolute(Register reg) { as.callAbsolute(reg); } public void ret() { as.ret(); }