mirror of https://github.com/aamine/cbc
* 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:
parent
4f1f681a7c
commit
637fce5053
43
ChangeLog
43
ChangeLog
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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++) {
|
||||||
|
|
|
||||||
|
|
@ -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 + ":";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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)));
|
||||||
|
|
|
||||||
|
|
@ -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 + ">";
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue