* introduce virtual stack again, for only local variables and tmp variables. Function arguments use true push & pop.

* --verbose-asm prints stack frame layout in detail.


git-svn-id: file:///Users/aamine/c/gitwork/public/cbc/trunk@4110 1b9489fe-b721-0410-924e-b54b9192deb8
This commit is contained in:
Minero Aoki 2008-12-14 15:05:20 +00:00
parent 3fa59ba6f8
commit f6a1df9142
15 changed files with 358 additions and 74 deletions

View File

@ -1,3 +1,10 @@
Mon Dec 15 00:05:16 2008 Minero Aoki <aamine@loveruby.net>
* introduce virtual stack again, for only local variables and tmp
variables. Function arguments use true push & pop.
* --verbose-asm prints stack frame layout in detail.
Sun Dec 14 21:04:56 2008 Minero Aoki <aamine@loveruby.net>
* test: test alloca more.

View File

@ -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
}
}

View File

@ -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);
}

View File

@ -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.
}
}

View File

@ -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");
}
}

View File

@ -22,4 +22,16 @@ public class DirectMemoryReference extends MemoryReference {
public String toSource(SymbolTable table) {
return this.value.toSource(table);
}
public int compareTo(MemoryReference mem) {
return -(mem.cmp(this));
}
protected int cmp(IndirectMemoryReference mem) {
return 1;
}
protected int cmp(DirectMemoryReference mem) {
return value.compareTo(mem.value);
}
}

View File

@ -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());
}
@ -54,4 +58,22 @@ public class IndirectMemoryReference extends MemoryReference {
return (offset.isZero() ? "" : offset.toSource(table))
+ "(" + base.toSource(table) + ")";
}
public int compareTo(MemoryReference mem) {
return -(mem.cmp(this));
}
protected int cmp(DirectMemoryReference mem) {
return -1;
}
protected int cmp(IndirectMemoryReference mem) {
int c = base.baseName().compareTo(mem.base.baseName());
if (c != 0) {
return c;
}
else {
return offset.compareTo(mem.offset);
}
}
}

View File

@ -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");

View File

@ -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,28 @@ public class IntegerLiteral implements Literal {
public void collectStatistics(AsmStatistics stats) {
// does nothing
}
public String toString() {
return "$" + value;
}
public int compareTo(Literal lit) {
return -(lit.cmp(this));
}
public int cmp(IntegerLiteral i) {
return new Long(value).compareTo(new Long(i.value));
}
public int cmp(NamedSymbol sym) {
return -1;
}
public int cmp(UnnamedSymbol sym) {
return -1;
}
public int cmp(SuffixedSymbol sym) {
return -1;
}
}

View File

@ -1,8 +1,13 @@
package net.loveruby.cflat.asm;
public interface Literal {
public interface Literal extends Comparable<Literal> {
public String toSource();
public String toSource(SymbolTable table);
public void collectStatistics(AsmStatistics stats);
public boolean isZero();
public Literal plus(long diff);
public int cmp(IntegerLiteral i);
public int cmp(NamedSymbol sym);
public int cmp(UnnamedSymbol sym);
public int cmp(SuffixedSymbol sym);
}

View File

@ -1,7 +1,11 @@
package net.loveruby.cflat.asm;
abstract public class MemoryReference extends AsmOperand {
abstract public class MemoryReference
extends AsmOperand implements Comparable<MemoryReference> {
public boolean isMemoryReference() {
return true;
}
abstract protected int cmp(DirectMemoryReference mem);
abstract protected int cmp(IndirectMemoryReference mem);
}

View File

@ -22,4 +22,24 @@ public class NamedSymbol extends BaseSymbol {
public String toString() {
return "#" + name;
}
public int compareTo(Literal lit) {
return -(lit.compareTo(this));
}
public int cmp(IntegerLiteral i) {
return 1;
}
public int cmp(NamedSymbol sym) {
return name.compareTo(sym.name);
}
public int cmp(UnnamedSymbol sym) {
return -1;
}
public int cmp(SuffixedSymbol sym) {
return toString().compareTo(sym.toString());
}
}

View File

@ -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();
}
@ -32,4 +36,24 @@ public class SuffixedSymbol implements Symbol {
public String toString() {
return base.toString() + suffix;
}
public int compareTo(Literal lit) {
return -(lit.compareTo(this));
}
public int cmp(IntegerLiteral i) {
return 1;
}
public int cmp(NamedSymbol sym) {
return toString().compareTo(sym.toString());
}
public int cmp(UnnamedSymbol sym) {
return -1;
}
public int cmp(SuffixedSymbol sym) {
return toString().compareTo(sym.toString());
}
}

View File

@ -20,4 +20,24 @@ public class UnnamedSymbol extends BaseSymbol {
public String toString() {
return super.toString();
}
public int compareTo(Literal lit) {
return -(lit.compareTo(this));
}
public int cmp(IntegerLiteral i) {
return 1;
}
public int cmp(NamedSymbol sym) {
return 1;
}
public int cmp(UnnamedSymbol sym) {
return toString().compareTo(sym.toString());
}
public int cmp(SuffixedSymbol sym) {
return 1;
}
}

View File

@ -286,6 +286,51 @@ public class CodeGenerator
// Compile Function
//
/* Standard IA-32 stack frame layout (after prologue)
*
* ======================= esp #3 (stack top just before function call)
* next arg 1
* ---------------------
* next arg 2
* ---------------------
* next arg 3
* --------------------- esp #2 (stack top after alloca call)
* alloca area
* --------------------- esp #1 (stack top just after prelude)
* temporary
* variables...
* --------------------- -16(%ebp)
* lvar 3
* --------------------- -12(%ebp)
* lvar 2
* --------------------- -8(%ebp)
* lvar 1
* --------------------- -4(%ebp)
* callee-saved register
* ======================= 0(%ebp)
* saved ebp
* --------------------- 4(%ebp)
* return address
* --------------------- 8(%ebp)
* arg 1
* --------------------- 12(%ebp)
* arg 2
* --------------------- 16(%ebp)
* arg 3
* ...
* ...
* ======================= stack bottom
*/
/*
* Platform Dependent Stack Parameters
*/
static final protected boolean stackGrowsLower = true;
static final protected long stackWordSize = 4;
static final protected long stackAlignment = stackWordSize;
// +1 for return address, +1 for saved bp
static final protected long paramStartWord = 2;
/** Compiles a function. */
// #@@range/compileFunction{
protected void compileFunction(DefinedFunction func) {
@ -304,13 +349,25 @@ public class CodeGenerator
// #@@}
protected void compileFunctionBody(DefinedFunction func) {
initVirtualStack();
List<Assembly> bodyAsms = compileStmts(func);
long maxTmpBytes = maxTmpBytes();
AsmStatistics stats = AsmStatistics.collect(bodyAsms);
bodyAsms = reduceLabels(bodyAsms, stats);
List<Register> saveRegs = usedCalleeSavedRegistersWithoutBP(stats);
long lvarBytes = allocateLocalVariables(func.body().scope(),
saveRegs.size());
prologue(func, saveRegs, lvarBytes);
long saveRegsBytes = saveRegs.size() * stackWordSize;
long lvarBytes = allocateLocalVariables(
func.body().scope(), saveRegsBytes);
fixTmpOffsets(bodyAsms, saveRegsBytes + lvarBytes);
if (options.isVerboseAsm()) {
printStackFrameLayout(
saveRegsBytes, lvarBytes, maxTmpBytes,
func.localVariables());
}
initVirtualStack();
prologue(func, saveRegs, saveRegsBytes + lvarBytes + maxTmpBytes);
if (options.isPositionIndependent()
&& stats.doesRegisterUsed(GOTBaseReg())) {
loadGOTBaseAddress(GOTBaseReg());
@ -319,6 +376,46 @@ public class CodeGenerator
epilogue(func, saveRegs, lvarBytes);
}
protected void printStackFrameLayout(
long saveRegsBytes, long lvarBytes, long maxTmpBytes,
List<DefinedVariable> lvars) {
List<MemInfo> vars = new ArrayList<MemInfo>();
for (DefinedVariable var : lvars) {
vars.add(new MemInfo(var.memref(), var.name()));
}
vars.add(new MemInfo(mem(0, bp()), "return address"));
vars.add(new MemInfo(mem(4, bp()), "saved %ebp"));
if (saveRegsBytes > 0) {
vars.add(new MemInfo(mem(-saveRegsBytes, bp()),
"saved callee-saved registers (" + saveRegsBytes + " bytes)"));
}
if (maxTmpBytes > 0) {
long offset = -(saveRegsBytes + lvarBytes + maxTmpBytes);
vars.add(new MemInfo(mem(offset, bp()),
"tmp variables (" + maxTmpBytes + " bytes)"));
}
Collections.sort(vars, new Comparator<MemInfo>() {
public int compare(MemInfo x, MemInfo y) {
return x.mem.compareTo(y.mem);
}
});
comment("---- Stack Frame Layout -----------");
for (MemInfo info : vars) {
comment(info.mem.toString() + ": " + info.name);
}
comment("-----------------------------------");
}
class MemInfo {
MemoryReference mem;
String name;
MemInfo(MemoryReference mem, String name) {
this.mem = mem;
this.name = name;
}
}
protected List<Assembly> compileStmts(DefinedFunction func) {
pushAssembler();
currentFunction = func;
@ -379,56 +476,14 @@ public class CodeGenerator
return calleeSavedRegistersCache;
}
/* Standard IA-32 stack frame layout (after prologue)
*
* ======================= esp (stack top)
* temporary
* variables...
* --------------------- ebp-(4*4)
* lvar 3
* --------------------- ebp-(4*3)
* lvar 2
* --------------------- ebp-(4*2)
* lvar 1
* --------------------- ebp-(4*1)
* callee-saved register
* ======================= ebp
* saved ebp
* --------------------- ebp+(4*1)
* return address
* --------------------- ebp+(4*2)
* arg 1
* --------------------- ebp+(4*3)
* arg 2
* --------------------- ebp+(4*4)
* arg 3
* ...
* ...
* ======================= stack bottom
*/
/*
* Platform Dependent Stack Parameters
*/
static final protected boolean stackGrowsLower = true;
static final protected long stackWordSize = 4;
static final protected long stackAlignment = stackWordSize;
// +1 for return address, +1 for saved bp
static final protected long paramStartWord = 2;
// #@@range/prologue{
protected void prologue(DefinedFunction func,
List<Register> saveRegs,
long lvarBytes) {
push(bp());
long frameSize) {
truePush(bp());
mov(sp(), bp());
saveRegisters(saveRegs);
extendStack(lvarBytes);
if (options.isVerboseAsm()) {
for (DefinedVariable var : func.localVariables()) {
comment("mem " + var.memref() + ": " + var.name());
}
}
extendStack(frameSize);
}
// #@@}
@ -436,16 +491,9 @@ public class CodeGenerator
protected void epilogue(DefinedFunction func,
List<Register> savedRegs,
long lvarBytes) {
//shrinkStack(lvarBytes);
if (! savedRegs.isEmpty()) {
long offset = stackGrowsLower
? -1 * savedRegs.size() * stackWordSize
: (savedRegs.size() - 1) * stackWordSize;
lea(mem(offset, bp()), sp());
restoreRegisters(savedRegs);
}
restoreRegisters(savedRegs);
mov(bp(), sp());
pop(bp());
truePop(bp());
ret();
}
// #@@}
@ -491,8 +539,7 @@ 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 * stackWordSize;
protected long allocateLocalVariables(LocalScope scope, long initLen) {
long maxLen = allocateScope(scope, initLen);
return maxLen - initLen;
}
@ -525,13 +572,75 @@ public class CodeGenerator
protected void extendStack(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) {
protected void rewindStack(long len) {
if (len > 0) {
add(imm(len * (stackGrowsLower ? 1 : -1)), sp());
if (stackGrowsLower) {
add(imm(len), sp());
}
else {
sub(imm(len), sp());
}
}
}
protected long stackPointer;
protected long stackPointerMax;
protected void initVirtualStack() {
stackPointer = 0;
stackPointerMax = stackPointer;
}
protected long maxTmpBytes() {
return stackPointerMax;
}
protected IndirectMemoryReference stackTop() {
if (stackGrowsLower) {
return mem(-stackPointer, bp());
}
else {
return mem(stackPointer - stackWordSize, bp());
}
}
protected void push(Register reg) {
extendVirtualStack(stackWordSize);
as.relocatableMov(reg, stackTop());
if (options.isVerboseAsm()) {
comment("push " + reg.name() + " -> " + stackTop());
}
}
protected void pop(Register reg) {
if (options.isVerboseAsm()) {
comment("pop " + reg.name() + " <- " + stackTop());
}
as.relocatableMov(stackTop(), reg);
rewindVirtualStack(stackWordSize);
}
protected void extendVirtualStack(long len) {
stackPointer += len;
stackPointerMax = Math.max(stackPointerMax, stackPointer);
}
protected void rewindVirtualStack(long len) {
stackPointer -= len;
}
protected void fixTmpOffsets(List<Assembly> asms, long offset) {
for (Assembly asm : asms) {
asm.fixStackOffset(offset * (stackGrowsLower ? -1 : 1));
}
}
@ -545,7 +654,7 @@ public class CodeGenerator
ListIterator<ExprNode> args = node.finalArg();
while (args.hasPrevious()) {
compile(args.previous());
push(reg("ax"));
truePush(reg("ax"));
}
// call
if (node.isStaticCall()) {
@ -559,7 +668,7 @@ public class CodeGenerator
}
// rewind stack
// >4 bytes arguments are not supported.
shrinkStack(node.numArgs() * stackWordSize);
rewindStack(node.numArgs() * stackWordSize);
}
public void visit(ReturnNode node) {
@ -1250,8 +1359,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(); }