mirror of https://github.com/aamine/cbc
r5032@macbookpro: aamine | 2009-06-07 03:03:18 +0900
* 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. git-svn-id: file:///Users/aamine/c/gitwork/public/cbc/trunk@4277 1b9489fe-b721-0410-924e-b54b9192deb8
This commit is contained in:
parent
0f036467ce
commit
4ac683c9d7
21
ChangeLog
21
ChangeLog
|
@ -1,3 +1,24 @@
|
|||
Sun Jun 7 03:02:35 2009 Minero Aoki <aamine@loveruby.net>
|
||||
|
||||
* 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 <aamine@loveruby.net>
|
||||
|
||||
* lib/alloca.s: shorten assembly.
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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() + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Register, Integer> registerUsage;
|
||||
|
|
|
@ -6,12 +6,14 @@ import java.util.ArrayList;
|
|||
import java.io.PrintStream;
|
||||
|
||||
public class AssemblyFile implements net.loveruby.cflat.sysdep.AssemblyFile {
|
||||
private final List<Assembly> assemblies;
|
||||
final Type naturalType;
|
||||
final long stackWordSize;
|
||||
final SymbolTable labelSymbols;
|
||||
final boolean verbose;
|
||||
private int commentIndentLevel;
|
||||
final VirtualStack virtualStack = new VirtualStack();
|
||||
private List<Assembly> assemblies = new ArrayList<Assembly>();
|
||||
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<Assembly>();
|
||||
this.commentIndentLevel = 0;
|
||||
initVirtualStack();
|
||||
}
|
||||
|
||||
List<Assembly> 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<Assembly> result = new ArrayList<Assembly>();
|
||||
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<IndirectMemoryReference> memrefs =
|
||||
new ArrayList<IndirectMemoryReference>();
|
||||
|
||||
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);
|
||||
}
|
||||
// #@@}
|
||||
|
||||
|
|
|
@ -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<Assembly> bodyAsms = optimize(body.assemblies());
|
||||
Statistics stats = Statistics.collect(bodyAsms);
|
||||
bodyAsms = reduceLabels(bodyAsms, stats);
|
||||
List<Register> 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<Register> 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<Assembly> optimize(List<Assembly> 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<Assembly> reduceLabels(
|
||||
List<Assembly> assemblies, Statistics stats) {
|
||||
List<Assembly> result = new ArrayList<Assembly>();
|
||||
for (Assembly asm : assemblies) {
|
||||
if (asm.isLabel() && ! stats.doesSymbolUsed((Label)asm)) {
|
||||
;
|
||||
}
|
||||
else {
|
||||
result.add(asm);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// #@@}
|
||||
|
||||
private List<Register> usedCalleeSavedRegistersWithoutBP(Statistics stats) {
|
||||
// does NOT include BP
|
||||
private List<Register> usedCalleeSavedRegisters(AssemblyFile asm) {
|
||||
List<Register> result = new ArrayList<Register>();
|
||||
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<Register> calleeSavedRegistersCache = null;
|
||||
|
||||
private List<Register> calleeSavedRegisters() {
|
||||
if (calleeSavedRegistersCache == null) {
|
||||
List<Register> regs = new ArrayList<Register>();
|
||||
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<Assembly> asms, long offset) {
|
||||
for (Assembly asm : asms) {
|
||||
asm.fixStackOffset(-offset);
|
||||
}
|
||||
}
|
||||
// #@@}
|
||||
|
||||
/**
|
||||
* Implements cdecl function call:
|
||||
* * All arguments are on stack.
|
||||
|
|
Loading…
Reference in New Issue