* 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>
* lib/Makefile: parameterize.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -41,6 +41,17 @@ public class Instruction extends Assembly {
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() {
return this.operands.length;
}
@ -53,6 +64,14 @@ public class Instruction extends Assembly {
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) {
stats.instructionUsed(mnemonic);
for (int i = 0; i < operands.length; i++) {

View File

@ -14,6 +14,10 @@ public class Label extends Assembly {
name = n;
}
public boolean isLabel() {
return true;
}
public long seq() {
return seq;
}
@ -22,6 +26,23 @@ public class Label extends Assembly {
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() {
return name + ":";
}

View File

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

View File

@ -1,4 +1,5 @@
package net.loveruby.cflat.asm;
import net.loveruby.cflat.utils.ClonableIterator;
import java.util.*;
public class PeepholeOptimizer implements AsmOptimizer {
@ -8,6 +9,10 @@ public class PeepholeOptimizer implements AsmOptimizer {
this.filters = defaultFilterSet();
}
public List optimize(List assemblies) {
return jumpElimination(insnOptimization(assemblies));
}
// List<Filter>
protected List defaultFilterSet() {
List set = new ArrayList();
@ -123,7 +128,7 @@ public class PeepholeOptimizer implements AsmOptimizer {
return new AnyRegisterPattern();
}
public List optimize(List assemblies) {
public List insnOptimization(List assemblies) {
List result = new ArrayList();
Iterator asms = assemblies.iterator();
while (asms.hasNext()) {
@ -205,4 +210,64 @@ public class PeepholeOptimizer implements AsmOptimizer {
interface InsnTemplate {
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;
}
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() {
return name;
}
@ -62,7 +78,7 @@ public class Register extends AsmOperand {
}
public void collectStatistics(AsmStatistics stats) {
stats.registerUsed(name);
stats.registerUsed(this);
}
public String toSource() {

View File

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