* net/loveruby/cflat/compiler/CodeGenerator.java: fix local variables offset after compiling function body, to allow saving really-used callee-saved registers only.

* net/loveruby/cflat/asm/IndirectMemoryReference.java: allow fixing offset out of consructor.
* net/loveruby/cflat/asm/AsmStatistics.java: new class.
* net/loveruby/cflat/asm/Assembly.java: support #collectStatistics.
* net/loveruby/cflat/asm/Instruction.java: ditto.
* net/loveruby/cflat/asm/AsmOperand.java: ditto.
* net/loveruby/cflat/asm/Register.java: ditto.
* net/loveruby/cflat/asm/AbsoluteAddress.java: ditto.
* net/loveruby/cflat/asm/DirectMemoryReference.java: ditto.
* net/loveruby/cflat/asm/ImmediateValue.java: ditto.
* net/loveruby/cflat/ast/Scope.java: refactoring: rename method: #allChildren -> #allScopes.
* net/loveruby/cflat/ast/Scope.java (allScopes): should include receiver scope itself.
* net/loveruby/cflat/ast/LocalScope.java (allVariables): did not wrongly included current scope's variables.
* net/loveruby/cflat/ast/LocalScope.java: refactoring: rename method: allVariables -> allLocalVariables.
* net/loveruby/cflat/ast/DefinedFunction.java: ditto.


git-svn-id: file:///Users/aamine/c/gitwork/public/cbc/trunk@4040 1b9489fe-b721-0410-924e-b54b9192deb8
This commit is contained in:
Minero Aoki 2008-09-20 18:04:20 +00:00
parent 076d0dea13
commit 1668b72403
15 changed files with 304 additions and 71 deletions

View File

@ -1,3 +1,43 @@
Sun Sep 21 03:04:16 2008 Minero Aoki <aamine@loveruby.net>
* net/loveruby/cflat/compiler/CodeGenerator.java: fix local
variables offset after compiling function body, to allow saving
really-used callee-saved registers only.
* net/loveruby/cflat/asm/IndirectMemoryReference.java: allow
fixing offset out of consructor.
* net/loveruby/cflat/asm/AsmStatistics.java: new class.
* net/loveruby/cflat/asm/Assembly.java: support
#collectStatistics.
* net/loveruby/cflat/asm/Instruction.java: ditto.
* net/loveruby/cflat/asm/AsmOperand.java: ditto.
* net/loveruby/cflat/asm/Register.java: ditto.
* net/loveruby/cflat/asm/AbsoluteAddress.java: ditto.
* net/loveruby/cflat/asm/DirectMemoryReference.java: ditto.
* net/loveruby/cflat/asm/ImmediateValue.java: ditto.
* net/loveruby/cflat/ast/Scope.java: refactoring: rename method:
#allChildren -> #allScopes.
* net/loveruby/cflat/ast/Scope.java (allScopes): should include
receiver scope itself.
* net/loveruby/cflat/ast/LocalScope.java (allVariables): did not
wrongly included current scope's variables.
* net/loveruby/cflat/ast/LocalScope.java: refactoring: rename
method: allVariables -> allLocalVariables.
* net/loveruby/cflat/ast/DefinedFunction.java: ditto.
Sat Sep 20 23:48:31 2008 Minero Aoki <aamine@loveruby.net>
* net/loveruby/cflat/compiler/Options.java: new option -O0, -O,

View File

@ -11,6 +11,10 @@ public class AbsoluteAddress extends AsmOperand {
return this.register;
}
public void collectStatistics(AsmStatistics stats) {
register.collectStatistics(stats);
}
public String toSource() {
return "*" + register.toSource();
}

View File

@ -15,6 +15,8 @@ abstract public class AsmOperand implements OperandPattern {
return null;
}
abstract public void collectStatistics(AsmStatistics stats);
// default implementation
public boolean match(AsmOperand operand) {
return equals(operand);

View File

@ -0,0 +1,52 @@
package net.loveruby.cflat.asm;
import java.util.*;
public class AsmStatistics {
protected Map registerUsage;
protected Map insnUsage;
static public AsmStatistics collect(List assemblies) {
AsmStatistics stats = new AsmStatistics();
Iterator asms = assemblies.iterator();
while (asms.hasNext()) {
Assembly asm = (Assembly)asms.next();
asm.collectStatistics(stats);
}
return stats;
}
public AsmStatistics() {
registerUsage = new HashMap();
insnUsage = new HashMap();
}
public int numRegisterUsage(String name) {
return fetchCount(registerUsage, name);
}
public void registerUsed(String name) {
incrementCount(registerUsage, name);
}
public int numInstructionUsage(String insn) {
return fetchCount(insnUsage, insn);
}
public void instructionUsed(String insn) {
incrementCount(insnUsage, insn);
}
protected int fetchCount(Map m, String name) {
Integer n = (Integer)m.get(name);
if (n == null) {
return 0;
}
else {
return n.intValue();
}
}
protected void incrementCount(Map m, String name) {
m.put(name, new Integer(fetchCount(m, name) + 1));
}
}

View File

@ -10,4 +10,8 @@ abstract public class Assembly {
public boolean isLabel() {
return false;
}
public void collectStatistics(AsmStatistics stats) {
// does nothing by default.
}
}

View File

@ -15,6 +15,10 @@ public class DirectMemoryReference extends MemoryReference {
return this.value;
}
public void collectStatistics(AsmStatistics stats) {
// does nothing
}
public String toSource() {
return this.value.toSource();
}

View File

@ -21,6 +21,10 @@ public class ImmediateValue extends AsmOperand {
return this.expr;
}
public void collectStatistics(AsmStatistics stats) {
// does nothing
}
public String toSource() {
return "$" + expr.toSource();
}

View File

@ -3,25 +3,44 @@ package net.loveruby.cflat.asm;
public class IndirectMemoryReference extends MemoryReference {
protected long offset;
protected Register base;
protected boolean fixed;
public IndirectMemoryReference(Register base) {
this(0, base);
this.offset = 0;
this.base = base;
this.fixed = false;
}
public IndirectMemoryReference(long offset, Register base) {
this.offset = offset;
this.base = base;
this.fixed = true;
}
public long offset() {
return offset;
}
public void fixOffset(long realOffset) {
if (fixed) {
throw new Error("must not happen: fixed = true");
}
this.offset = realOffset;
this.fixed = true;
}
public Register base() {
return base;
}
public void collectStatistics(AsmStatistics stats) {
base.collectStatistics(stats);
}
public String toSource() {
if (! fixed) {
throw new Error("must not happen: writing unfixed variable");
}
return (offset == 0 ? "" : "" + offset) + "(" + base.toSource() + ")";
}
}

View File

@ -53,6 +53,13 @@ public class Instruction extends Assembly {
return this.operands[1];
}
public void collectStatistics(AsmStatistics stats) {
stats.instructionUsed(mnemonic);
for (int i = 0; i < operands.length; i++) {
operands[i].collectStatistics(stats);
}
}
public String toSource() {
StringBuffer buf = new StringBuffer();
buf.append("\t");

View File

@ -61,6 +61,10 @@ public class Register extends AsmOperand {
return false;
}
public void collectStatistics(AsmStatistics stats) {
stats.registerUsed(name);
}
public String toSource() {
return "%" + name();
}

View File

@ -44,7 +44,7 @@ public class DefinedFunction extends Function {
* Does NOT include static local variables.
*/
public Iterator localVariables() {
return scope.allVariables();
return scope.allLocalVariables();
}
class JumpEntry {

View File

@ -38,8 +38,9 @@ public class DefinedVariable extends Variable {
}
public MemoryReference memref() {
if (memref == null)
if (memref == null) {
throw new Error("unresolved variable address");
}
return memref;
}

View File

@ -19,14 +19,21 @@ public class LocalScope extends Scope {
return children.iterator();
}
// Returns local variables defined in this scope.
// Does includes all nested local variables.
// Does NOT include static local variables.
/**
* Returns local variables defined in this scope.
* Does NOT includes children's local variables.
* Does NOT include static local variables.
*/
public Iterator variables() {
return variablesList().iterator();
return lvarList().iterator();
}
protected List variablesList() {
/**
* Returns local variables defined in this scope.
* Does NOT includes children's local variables.
* Does NOT include static local variables.
*/
protected List lvarList() {
List result = new ArrayList();
Iterator ents = entities.values().iterator();
while (ents.hasNext()) {
@ -41,9 +48,13 @@ public class LocalScope extends Scope {
return result;
}
/**
* Returns the number of all entities in this scope.
* Result includes the number of children's entities.
*/
public long numAllEntities() {
if (numAllEntities < 0) {
Iterator cs = allChildren();
Iterator cs = allScopes().iterator();
long n = 0;
while (cs.hasNext()) {
Scope c = (Scope)cs.next();
@ -54,26 +65,32 @@ public class LocalScope extends Scope {
return numAllEntities;
}
// Returns all function local variables defined in this scope.
// Does includes all nested local variables.
// Does NOT include static local variables.
public Iterator allVariables() {
return allEntities().iterator();
/**
* Returns all local variables in this scope.
* The result DOES includes all nested local variables,
* while it does NOT include static local variables.
*/
public Iterator allLocalVariables() {
return allLocalVariablesList().iterator();
}
protected List allEntities() {
// List<DefinedVariable>
protected List allLocalVariablesList() {
List result = new ArrayList();
Iterator scopes = allChildren();
Iterator scopes = allScopes().iterator();
while (scopes.hasNext()) {
LocalScope s = (LocalScope)scopes.next();
result.addAll(s.variablesList());
result.addAll(s.lvarList());
}
return result;
}
/**
* Returns all static local variables defined in this scope.
*/
public List staticLocalVariables() {
List result = new ArrayList();
Iterator scopes = allChildren();
Iterator scopes = allScopes().iterator();
while (scopes.hasNext()) {
LocalScope s = (LocalScope)scopes.next();
Iterator vars = s.entities.values().iterator();

View File

@ -37,20 +37,19 @@ abstract public class Scope {
children.add(s);
}
// Returns a list of all child scopes.
// Does NOT include myself.
protected Iterator allChildren() {
// Returns a list of all child scopes including this scope.
protected List allScopes() {
List result = new ArrayList();
collectChildren(result);
return result.iterator();
collectScope(result);
return result;
}
protected void collectChildren(List buf) {
protected void collectScope(List buf) {
buf.add(this);
Iterator cs = children.iterator();
while (cs.hasNext()) {
Scope c = (Scope)cs.next();
buf.add(c);
c.collectChildren(buf);
c.collectScope(buf);
}
}

View File

@ -187,28 +187,35 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
protected void compileFunction(DefinedFunction func) {
long numSavedRegs = 0; // 1 for PIC
allocateParameters(func);
long lvarBytes = allocateLocalVariables(func, numSavedRegs);
allocateLocalVariablesTemp(func.body().scope());
List bodyAsms = compileFunctionBody(func);
AsmStatistics stats = AsmStatistics.collect(bodyAsms);
List usedCalleeSavedRegs = usedCalleeSavedRegs(stats);
long lvarBytes = allocateLocalVariables(func.body().scope(),
usedCalleeSavedRegs.size());
currentFunction = func;
String symbol = csymbol(func.name());
if (! func.isPrivate()) {
_globl(symbol);
}
_type(symbol, "@function");
label(symbol);
prologue(func, lvarBytes);
compileFunctionBody(func.body());
epilogue(func, lvarBytes);
prologue(func, usedCalleeSavedRegs, lvarBytes);
as.addAll(bodyAsms);
epilogue(func, usedCalleeSavedRegs, lvarBytes);
_size(symbol, ".-" + symbol);
}
// #@@}
protected void compileFunctionBody(Node body) {
protected List compileFunctionBody(DefinedFunction func) {
currentFunction = func;
this.as = newAssembler();
compile(body);
compile(func.body());
List assemblies = this.as.assemblies();
this.as = this.assembler;
this.as.addAll(optimizer.optimize(assemblies));
currentFunction = null;
return optimizer.optimize(assemblies);
}
// #@@range/compile{
@ -231,47 +238,45 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
}
// #@@}
// #@@range/prologue{
protected void prologue(DefinedFunction func, long lvarBytes) {
push(bp());
mov(sp(), bp());
extendStack(lvarBytes);
protected List usedCalleeSavedRegs(AsmStatistics stats) {
List result = new ArrayList();
Iterator regs = calleeSavedRegisters().iterator();
while (regs.hasNext()) {
Register reg = (Register)regs.next();
if (stats.numRegisterUsage(reg.baseName()) > 0) {
result.add(reg);
}
}
return result;
}
// #@@}
// #@@range/epilogue{
protected void epilogue(DefinedFunction func, long lvarBytes) {
label(epilogueLabel(func));
shrinkStack(lvarBytes);
mov(bp(), sp());
pop(bp());
ret();
}
// #@@}
protected List calleeSavedRegistersCache = null;
// #@@range/jmpEpilogue{
protected void jmpEpilogue() {
jmp(new Label(epilogueLabel(currentFunction)));
protected List calleeSavedRegisters() {
if (calleeSavedRegistersCache == null) {
ArrayList regs = new ArrayList();
regs.add(reg("bx"));
regs.add(reg("si"));
regs.add(reg("di"));
regs.add(reg("bp"));
calleeSavedRegistersCache = regs;
}
return calleeSavedRegistersCache;
}
// #@@}
// #@@range/epilogueLabel{
protected String epilogueLabel(DefinedFunction func) {
return ".L" + func.name() + "$epilogue";
}
// #@@}
/* Standard IA-32 stack frame layout (after prologue)
*
* ======================= esp (stack top)
* temporary
* variables...
* --------------------- ebp-(4*3)
* --------------------- ebp-(4*4)
* lvar 3
* --------------------- ebp-(4*2)
* --------------------- ebp-(4*3)
* lvar 2
* --------------------- ebp-(4*1)
* --------------------- ebp-(4*2)
* lvar 1
* --------------------- ebp-(4*1)
* callee-saved register
* ======================= ebp
* saved ebp
* --------------------- ebp+(4*1)
@ -296,6 +301,59 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
// +1 for return address, +1 for saved bp
static final protected long paramStartWord = 2;
// #@@range/prologue{
protected void prologue(DefinedFunction func,
List saveRegs, long lvarBytes) {
push(bp());
mov(sp(), bp());
Iterator regs = saveRegs.iterator();
while (regs.hasNext()) {
Register reg = (Register)regs.next();
// bp is already saved
if (! reg.baseName().equals("bp")) {
push(reg);
}
}
extendStack(lvarBytes);
Iterator vars = func.localVariables();
while (vars.hasNext()) {
DefinedVariable var = (DefinedVariable)vars.next();
comment("mem " + var.memref().toSource() + ": " + var.name());
}
}
// #@@}
// #@@range/epilogue{
protected void epilogue(DefinedFunction func,
List savedRegs, long lvarBytes) {
label(epilogueLabel(func));
shrinkStack(lvarBytes);
Iterator regs = savedRegs.iterator();
while (regs.hasNext()) {
Register reg = (Register)regs.next();
if (! reg.baseName().equals("bp")) {
pop(reg);
}
}
mov(bp(), sp());
pop(bp());
ret();
}
// #@@}
// #@@range/jmpEpilogue{
protected void jmpEpilogue() {
jmp(new Label(epilogueLabel(currentFunction)));
}
// #@@}
// #@@range/epilogueLabel{
protected String epilogueLabel(DefinedFunction func) {
return ".L" + func.name() + "$epilogue";
}
// #@@}
protected void allocateParameters(DefinedFunction func) {
Iterator vars = func.parameters();
long word = paramStartWord;
@ -311,12 +369,26 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
}
}
// Fixes addresses of local variables.
// Returns byte-length of the local variable area.
protected long allocateLocalVariables(DefinedFunction func,
long numSavedRegs) {
long initLen = numSavedRegs * stackWordSize;
long maxLen = allocateScope(func.body().scope(), initLen);
/**
* Allocates addresses of local variables, but offset is still
* not determined, assign unfixed IndirectMemoryReference.
*/
protected void allocateLocalVariablesTemp(LocalScope scope) {
Iterator vars = scope.allLocalVariables();
while (vars.hasNext()) {
DefinedVariable var = (DefinedVariable)vars.next();
var.setMemref(new IndirectMemoryReference(bp()));
}
}
/**
* Fixes addresses of local variables.
* 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;
}
@ -327,10 +399,10 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
DefinedVariable var = (DefinedVariable)vars.next();
if (stackGrowsLower) {
len = Assembler.align(len + var.allocSize(), stackAlignment);
var.setMemref(mem(-len, bp()));
fixMemref((IndirectMemoryReference)var.memref(), -len);
}
else {
var.setMemref(mem(len, bp()));
fixMemref((IndirectMemoryReference)var.memref(), len);
len = Assembler.align(len + var.allocSize(), stackAlignment);
}
}
@ -346,6 +418,10 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
return maxLen;
}
protected void fixMemref(IndirectMemoryReference memref, long offset) {
memref.fixOffset(offset);
}
protected void extendStack(long len) {
if (len > 0) {
add(imm(len * (stackGrowsLower ? -1 : 1)), sp());
@ -886,7 +962,7 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
}
protected IndirectMemoryReference mem(Register reg) {
return new IndirectMemoryReference(reg);
return new IndirectMemoryReference(0, reg);
}
protected IndirectMemoryReference mem(long offset, Register reg) {