* net/loveruby/cflat/compiler/CodeGenerator.java: apply jump elimination.

* net/loveruby/cflat/asm/PeepholeOptimizer.java: new optimization method: jump elimination.
* net/loveruby/cflat/asm/Assembler.java: refactoring: #string -> #toSource.
* net/loveruby/cflat/asm/Assembler.java: refactoring: list -> assemblies.
* net/loveruby/cflat/asm/Assembly.java: new method #isDirective and #isComment.
* net/loveruby/cflat/asm/Directive.java: implement it.
* net/loveruby/cflat/asm/AsmComment.java: implement it.
* net/loveruby/cflat/asm/Label.java: implement it.
* net/loveruby/cflat/asm/Label.java: new method #equals, #hashCode.
* net/loveruby/cflat/asm/Instruction.java: add jump related methods to analyze jump instruction.
* net/loveruby/cflat/asm/LabelRef.java: new method #label to allow extracting a Label.
* net/loveruby/cflat/asm/Register.java: new method #equals, #hashCode.
* net/loveruby/cflat/asm/AsmStatistics.java: use Object for map keys.
* net/loveruby/cflat/asm/AsmStatistics.java: new method #doesRegisterUsed.
* net/loveruby/cflat/utils/ClonableIterator.java: new utility.


git-svn-id: file:///Users/aamine/c/gitwork/public/cbc/trunk@4050 1b9489fe-b721-0410-924e-b54b9192deb8
This commit is contained in:
Minero Aoki 2008-09-23 13:50:54 +00:00
parent 4f1f681a7c
commit 637fce5053
13 changed files with 315 additions and 70 deletions

View File

@ -1,3 +1,46 @@
Tue Sep 23 22:50:52 2008 Minero Aoki <aamine@loveruby.net>
* net/loveruby/cflat/compiler/CodeGenerator.java: apply jump
elimination.
* net/loveruby/cflat/asm/PeepholeOptimizer.java: new optimization
method: jump elimination.
* net/loveruby/cflat/asm/Assembler.java: refactoring: #string ->
#toSource.
* net/loveruby/cflat/asm/Assembler.java: refactoring: list ->
assemblies.
* net/loveruby/cflat/asm/Assembly.java: new method #isDirective
and #isComment.
* net/loveruby/cflat/asm/Directive.java: implement it.
* net/loveruby/cflat/asm/AsmComment.java: implement it.
* net/loveruby/cflat/asm/Label.java: implement it.
* net/loveruby/cflat/asm/Label.java: new method #equals,
#hashCode.
* net/loveruby/cflat/asm/Instruction.java: add jump related
methods to analyze jump instruction.
* net/loveruby/cflat/asm/LabelRef.java: new method #label to allow
extracting a Label.
* net/loveruby/cflat/asm/Register.java: new method #equals,
#hashCode.
* net/loveruby/cflat/asm/AsmStatistics.java: use Object for map
keys.
* net/loveruby/cflat/asm/AsmStatistics.java: new method
#doesRegisterUsed.
* net/loveruby/cflat/utils/ClonableIterator.java: new utility.
Tue Sep 23 22:45:00 2008 Minero Aoki <aamine@loveruby.net> Tue Sep 23 22:45:00 2008 Minero Aoki <aamine@loveruby.net>
* lib/Makefile: parameterize. * lib/Makefile: parameterize.

View File

@ -13,6 +13,10 @@ public class AsmComment extends Assembly {
this.indentLevel = indentLevel; this.indentLevel = indentLevel;
} }
public boolean isComment() {
return true;
}
public String toSource() { public String toSource() {
return "\t" + indent() + "# " + string; return "\t" + indent() + "# " + string;
} }

View File

@ -20,12 +20,16 @@ public class AsmStatistics {
insnUsage = new HashMap(); insnUsage = new HashMap();
} }
public int numRegisterUsage(String name) { public boolean doesRegisterUsed(Register reg) {
return fetchCount(registerUsage, name); return numRegisterUsage(reg) > 0;
} }
public void registerUsed(String name) { public int numRegisterUsage(Register reg) {
incrementCount(registerUsage, name); return fetchCount(registerUsage, reg);
}
public void registerUsed(Register reg) {
incrementCount(registerUsage, reg);
} }
public int numInstructionUsage(String insn) { public int numInstructionUsage(String insn) {
@ -36,8 +40,8 @@ public class AsmStatistics {
incrementCount(insnUsage, insn); incrementCount(insnUsage, insn);
} }
protected int fetchCount(Map m, String name) { protected int fetchCount(Map m, Object key) {
Integer n = (Integer)m.get(name); Integer n = (Integer)m.get(key);
if (n == null) { if (n == null) {
return 0; return 0;
} }
@ -46,7 +50,7 @@ public class AsmStatistics {
} }
} }
protected void incrementCount(Map m, String name) { protected void incrementCount(Map m, Object key) {
m.put(name, new Integer(fetchCount(m, name) + 1)); m.put(key, new Integer(fetchCount(m, key) + 1));
} }
} }

View File

@ -4,7 +4,7 @@ import net.loveruby.cflat.utils.*;
import java.util.*; import java.util.*;
public class Assembler { public class Assembler {
protected List list; // List<Assembly> protected List assemblies; // List<Assembly>
protected Type naturalType; protected Type naturalType;
protected int commentIndentLevel; protected int commentIndentLevel;
@ -13,24 +13,24 @@ public class Assembler {
} }
public Assembler(Type naturalType) { public Assembler(Type naturalType) {
this.list = new ArrayList(); this.assemblies = new ArrayList();
this.naturalType = naturalType; this.naturalType = naturalType;
this.commentIndentLevel = 0; this.commentIndentLevel = 0;
} }
public List assemblies() { public List assemblies() {
return this.list; return this.assemblies;
} }
public void addAll(List assemblies) { public void addAll(List assemblies) {
this.list.addAll(assemblies); this.assemblies.addAll(assemblies);
} }
public String string() { public String toSource() {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
Iterator i = list.iterator(); Iterator asms = assemblies.iterator();
while (i.hasNext()) { while (asms.hasNext()) {
Assembly asm = (Assembly)i.next(); Assembly asm = (Assembly)asms.next();
buf.append(asm.toSource()); buf.append(asm.toSource());
buf.append("\n"); buf.append("\n");
} }
@ -38,7 +38,7 @@ public class Assembler {
} }
public void comment(String str) { public void comment(String str) {
list.add(new AsmComment(str, commentIndentLevel)); assemblies.add(new AsmComment(str, commentIndentLevel));
} }
public void indentComment() { public void indentComment() {
@ -50,39 +50,39 @@ public class Assembler {
} }
public void label(String sym) { public void label(String sym) {
list.add(new Label(sym)); assemblies.add(new Label(sym));
} }
public void label(Label label) { public void label(Label label) {
list.add(label); assemblies.add(label);
} }
protected void directive(String direc) { protected void directive(String direc) {
list.add(new Directive(direc)); assemblies.add(new Directive(direc));
} }
protected void insn(String op) { protected void insn(String op) {
list.add(new Instruction(op)); assemblies.add(new Instruction(op));
} }
protected void insn(String op, AsmOperand a) { protected void insn(String op, AsmOperand a) {
list.add(new Instruction(op, "", a)); assemblies.add(new Instruction(op, "", a));
} }
protected void insn(String op, String suffix, AsmOperand a) { protected void insn(String op, String suffix, AsmOperand a) {
list.add(new Instruction(op, suffix, a)); assemblies.add(new Instruction(op, suffix, a));
} }
protected void insn(Type t, String op, AsmOperand a) { protected void insn(Type t, String op, AsmOperand a) {
list.add(new Instruction(op, typeSuffix(t), a)); assemblies.add(new Instruction(op, typeSuffix(t), a));
} }
protected void insn(String op, String suffix, AsmOperand a, AsmOperand b) { protected void insn(String op, String suffix, AsmOperand a, AsmOperand b) {
list.add(new Instruction(op, suffix, a, b)); assemblies.add(new Instruction(op, suffix, a, b));
} }
protected void insn(Type t, String op, AsmOperand a, AsmOperand b) { protected void insn(Type t, String op, AsmOperand a, AsmOperand b) {
list.add(new Instruction(op, typeSuffix(t), a, b)); assemblies.add(new Instruction(op, typeSuffix(t), a, b));
} }
protected String typeSuffix(Type t1, Type t2) { protected String typeSuffix(Type t1, Type t2) {

View File

@ -11,6 +11,14 @@ abstract public class Assembly {
return false; return false;
} }
public boolean isDirective() {
return false;
}
public boolean isComment() {
return false;
}
public void collectStatistics(AsmStatistics stats) { public void collectStatistics(AsmStatistics stats) {
// does nothing by default. // does nothing by default.
} }

View File

@ -7,6 +7,10 @@ public class Directive extends Assembly {
this.content = content; this.content = content;
} }
public boolean isDirective() {
return true;
}
public String toSource() { public String toSource() {
return this.content; return this.content;
} }

View File

@ -41,6 +41,17 @@ public class Instruction extends Assembly {
return this.mnemonic; return this.mnemonic;
} }
public boolean isJumpInstruction() {
return mnemonic.equals("jmp")
|| mnemonic.equals("jz")
|| mnemonic.equals("jne")
|| mnemonic.equals("je")
|| mnemonic.equals("jne");
}
/**
* Returns the number of operands.
*/
public int numOperands() { public int numOperands() {
return this.operands.length; return this.operands.length;
} }
@ -53,6 +64,14 @@ public class Instruction extends Assembly {
return this.operands[1]; return this.operands[1];
} }
/**
* Extract jump destination label from operands.
*/
public Label jmpDestination() {
DirectMemoryReference ref = (DirectMemoryReference)(operands[0]);
return ((LabelRef)ref.value()).label();
}
public void collectStatistics(AsmStatistics stats) { public void collectStatistics(AsmStatistics stats) {
stats.instructionUsed(mnemonic); stats.instructionUsed(mnemonic);
for (int i = 0; i < operands.length; i++) { for (int i = 0; i < operands.length; i++) {

View File

@ -14,6 +14,10 @@ public class Label extends Assembly {
name = n; name = n;
} }
public boolean isLabel() {
return true;
}
public long seq() { public long seq() {
return seq; return seq;
} }
@ -22,6 +26,23 @@ public class Label extends Assembly {
return name; return name;
} }
public boolean equals(Object other) {
if (other instanceof Label) {
return equals((Label)other);
}
else {
return false;
}
}
public int hashCode() {
return name.hashCode();
}
public boolean equals(Label label) {
return name.equals(label.name());
}
public String toSource() { public String toSource() {
return name + ":"; return name + ":";
} }

View File

@ -7,6 +7,10 @@ public class LabelRef extends Literal {
this.label = label; this.label = label;
} }
public Label label() {
return label;
}
public String symbol() { public String symbol() {
return label.name(); return label.name();
} }

View File

@ -1,4 +1,5 @@
package net.loveruby.cflat.asm; package net.loveruby.cflat.asm;
import net.loveruby.cflat.utils.ClonableIterator;
import java.util.*; import java.util.*;
public class PeepholeOptimizer implements AsmOptimizer { public class PeepholeOptimizer implements AsmOptimizer {
@ -8,6 +9,10 @@ public class PeepholeOptimizer implements AsmOptimizer {
this.filters = defaultFilterSet(); this.filters = defaultFilterSet();
} }
public List optimize(List assemblies) {
return jumpElimination(insnOptimization(assemblies));
}
// List<Filter> // List<Filter>
protected List defaultFilterSet() { protected List defaultFilterSet() {
List set = new ArrayList(); List set = new ArrayList();
@ -123,7 +128,7 @@ public class PeepholeOptimizer implements AsmOptimizer {
return new AnyRegisterPattern(); return new AnyRegisterPattern();
} }
public List optimize(List assemblies) { public List insnOptimization(List assemblies) {
List result = new ArrayList(); List result = new ArrayList();
Iterator asms = assemblies.iterator(); Iterator asms = assemblies.iterator();
while (asms.hasNext()) { while (asms.hasNext()) {
@ -205,4 +210,64 @@ public class PeepholeOptimizer implements AsmOptimizer {
interface InsnTemplate { interface InsnTemplate {
abstract public Instruction apply(Instruction insn); abstract public Instruction apply(Instruction insn);
} }
//
// jumpElimination
//
public List jumpElimination(List assemblies) {
List result = new ArrayList();
ClonableIterator asms = new ClonableIterator(assemblies);
while (asms.hasNext()) {
Assembly asm = (Assembly)asms.next();
if (isUselessJump(asm, asms)) {
; // remove useless jump
}
else {
result.add(asm);
}
}
return result;
}
protected boolean isUselessJump(Assembly asm, ClonableIterator asms) {
if (! asm.isInstruction()) return false;
Instruction insn = (Instruction)asm;
if (! insn.isJumpInstruction()) return false;
return doesLabelFollows(asms.dup(), insn.jmpDestination());
}
/**
* Returns true if jmpDest is found in asms before any instruction
* or directives. For example, this method returns true if contents
* of asms are:
*
* if_end3:
* # comment
* jmpDest:
* mov
* mov
* add
*/
protected boolean doesLabelFollows(ClonableIterator asms, Label jmpDest) {
while (asms.hasNext()) {
Assembly asm = (Assembly)asms.next();
if (asm.isLabel()) {
Label label = (Label)asm;
if (label.equals(jmpDest)) {
return true;
}
else {
continue;
}
}
else if (asm.isComment()) {
continue;
}
else {
return false;
}
}
return false;
}
} }

View File

@ -32,6 +32,22 @@ public class Register extends AsmOperand {
return true; return true;
} }
public boolean equals(Object other) {
if (!(other instanceof Register)) return false;
return equals((Register)other);
}
public int hashCode() {
return name.hashCode();
}
/**
* size difference does NOT matter.
*/
public boolean equals(Register reg) {
return name.equals(reg.baseName());
}
public String baseName() { public String baseName() {
return name; return name;
} }
@ -62,7 +78,7 @@ public class Register extends AsmOperand {
} }
public void collectStatistics(AsmStatistics stats) { public void collectStatistics(AsmStatistics stats) {
stats.registerUsed(name); stats.registerUsed(this);
} }
public String toSource() { public String toSource() {

View File

@ -9,7 +9,7 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
protected AsmOptimizer optimizer; protected AsmOptimizer optimizer;
protected ErrorHandler errorHandler; protected ErrorHandler errorHandler;
protected boolean verboseAsm; protected boolean verboseAsm;
protected Assembler assembler; protected LinkedList asStack;
protected Assembler as; protected Assembler as;
protected TypeTable typeTable; protected TypeTable typeTable;
protected DefinedFunction currentFunction; protected DefinedFunction currentFunction;
@ -20,6 +20,7 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
this.optimizer = optimizer; this.optimizer = optimizer;
this.errorHandler = errorHandler; this.errorHandler = errorHandler;
this.verboseAsm = verboseAsm; this.verboseAsm = verboseAsm;
this.asStack = new LinkedList();
} }
// #@@} // #@@}
@ -27,12 +28,26 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
// #@@range/generate // #@@range/generate
public String generate(AST ast) { public String generate(AST ast) {
this.typeTable = ast.typeTable(); this.typeTable = ast.typeTable();
this.assembler = newAssembler(); pushAssembler();
this.as = this.assembler;
allocateGlobalVariables(ast.globalVariables()); allocateGlobalVariables(ast.globalVariables());
allocateCommonSymbols(ast.commonSymbols()); allocateCommonSymbols(ast.commonSymbols());
compileAST(ast); compileAST(ast);
return as.string(); return popAssembler().toSource();
}
protected void pushAssembler() {
asStack.add(newAssembler());
this.as = (Assembler)asStack.getLast();
}
protected Assembler popAssembler() {
Assembler poped = (Assembler)asStack.removeLast();
this.as = asStack.isEmpty() ? null : (Assembler)asStack.getLast();
return poped;
}
protected Assembler newAssembler() {
return new Assembler(typeTable.unsignedLong());
} }
public void compileAST(AST ast) { public void compileAST(AST ast) {
@ -54,10 +69,6 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
} }
// #@@} // #@@}
protected Assembler newAssembler() {
return new Assembler(typeTable.unsignedLong());
}
/** /**
* Sets memory reference for... * Sets memory reference for...
* * public global variables * * public global variables
@ -189,37 +200,38 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
/** Compiles a function. */ /** Compiles a function. */
// #@@range/compileFunction{ // #@@range/compileFunction{
protected void compileFunction(DefinedFunction func) { protected void compileFunction(DefinedFunction func) {
long numSavedRegs = 0; // 1 for PIC
allocateParameters(func); allocateParameters(func);
allocateLocalVariablesTemp(func.body().scope()); 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());
String symbol = csymbol(func.name()); String symbol = csymbol(func.name());
if (! func.isPrivate()) { if (! func.isPrivate()) {
_globl(symbol); _globl(symbol);
} }
_type(symbol, "@function"); _type(symbol, "@function");
label(symbol); label(symbol);
prologue(func, usedCalleeSavedRegs, lvarBytes); compileFunctionBody(func);
as.addAll(bodyAsms);
epilogue(func, usedCalleeSavedRegs, lvarBytes);
_size(symbol, ".-" + symbol); _size(symbol, ".-" + symbol);
} }
// #@@} // #@@}
protected List compileFunctionBody(DefinedFunction func) { protected void compileFunctionBody(DefinedFunction func) {
List bodyAsms = compileStmts(func);
AsmStatistics stats = AsmStatistics.collect(bodyAsms);
List saveRegs = usedCalleeSavedRegisters(stats);
long lvarBytes = allocateLocalVariables(func.body().scope(),
saveRegs.size());
prologue(func, saveRegs, lvarBytes);
as.addAll(bodyAsms);
epilogue(func, saveRegs, lvarBytes);
}
protected List compileStmts(DefinedFunction func) {
pushAssembler();
currentFunction = func; currentFunction = func;
this.as = newAssembler();
compile(func.body()); compile(func.body());
List assemblies = this.as.assemblies(); label(epilogueLabel(func));
this.as = this.assembler;
currentFunction = null; currentFunction = null;
return optimizer.optimize(assemblies); return optimizer.optimize(popAssembler().assemblies());
} }
// #@@range/compile{ // #@@range/compile{
@ -250,12 +262,12 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
} }
// #@@} // #@@}
protected List usedCalleeSavedRegs(AsmStatistics stats) { protected List usedCalleeSavedRegisters(AsmStatistics stats) {
List result = new ArrayList(); List result = new ArrayList();
Iterator regs = calleeSavedRegisters().iterator(); Iterator regs = calleeSavedRegisters().iterator();
while (regs.hasNext()) { while (regs.hasNext()) {
Register reg = (Register)regs.next(); Register reg = (Register)regs.next();
if (stats.numRegisterUsage(reg.baseName()) > 0) { if (stats.doesRegisterUsed(reg)) {
result.add(reg); result.add(reg);
} }
} }
@ -318,16 +330,8 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
List saveRegs, long lvarBytes) { List saveRegs, long lvarBytes) {
push(bp()); push(bp());
mov(sp(), bp()); mov(sp(), bp());
Iterator regs = saveRegs.iterator(); saveRegisters(saveRegs);
while (regs.hasNext()) {
Register reg = (Register)regs.next();
// bp is already saved
if (! reg.baseName().equals("bp")) {
push(reg);
}
}
extendStack(lvarBytes); extendStack(lvarBytes);
if (verboseAsm) { if (verboseAsm) {
Iterator vars = func.localVariables(); Iterator vars = func.localVariables();
while (vars.hasNext()) { while (vars.hasNext()) {
@ -341,21 +345,34 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
// #@@range/epilogue{ // #@@range/epilogue{
protected void epilogue(DefinedFunction func, protected void epilogue(DefinedFunction func,
List savedRegs, long lvarBytes) { List savedRegs, long lvarBytes) {
label(epilogueLabel(func));
shrinkStack(lvarBytes); shrinkStack(lvarBytes);
Iterator regs = savedRegs.iterator(); restoreRegisters(savedRegs);
while (regs.hasNext()) {
Register reg = (Register)regs.next();
if (! reg.baseName().equals("bp")) {
pop(reg);
}
}
mov(bp(), sp()); mov(bp(), sp());
pop(bp()); pop(bp());
ret(); ret();
} }
// #@@} // #@@}
protected void saveRegisters(List saveRegs) {
Iterator regs = saveRegs.iterator();
while (regs.hasNext()) {
Register reg = (Register)regs.next();
if (! reg.equals(bp())) { // bp is already saved.
push(reg);
}
}
}
protected void restoreRegisters(List savedRegs) {
Iterator regs = savedRegs.iterator();
while (regs.hasNext()) {
Register reg = (Register)regs.next();
if (! reg.equals(bp())) { // bp is going to be restored.
pop(reg);
}
}
}
// #@@range/jmpEpilogue{ // #@@range/jmpEpilogue{
protected void jmpEpilogue() { protected void jmpEpilogue() {
jmp(new Label(epilogueLabel(currentFunction))); jmp(new Label(epilogueLabel(currentFunction)));

View File

@ -0,0 +1,40 @@
package net.loveruby.cflat.utils;
import java.util.*;
public class ClonableIterator implements Iterator {
protected List list;
protected int index;
public ClonableIterator(List list) {
this(list, 0);
}
protected ClonableIterator(List list, int index) {
this.list = list;
this.index = index;
}
public Object clone() {
return new ClonableIterator(list, index);
}
public ClonableIterator dup() {
return new ClonableIterator(list, index);
}
public boolean hasNext() {
return index < list.size();
}
public Object next() {
return list.get(index++);
}
public void remove() {
list.remove(index);
}
public String toString() {
return "#<ClonableIterator list=" + list + " index=" + index + ">";
}
}