* net/loveruby/cflat/asm/PeepholeOptimizer.java: unify insn optimization and jump elimination.

* net/loveruby/cflat/utils/ClonableIterator.java -> Cursor.java
* net/loveruby/cflat/compiler/Options.java: use default optimization rule set for -O.


git-svn-id: file:///Users/aamine/c/gitwork/public/cbc/trunk@4052 1b9489fe-b721-0410-924e-b54b9192deb8
This commit is contained in:
Minero Aoki 2008-09-23 15:48:39 +00:00
parent d32b629568
commit df96fa80c7
4 changed files with 176 additions and 125 deletions

View File

@ -1,3 +1,13 @@
Wed Sep 24 00:48:37 2008 Minero Aoki <aamine@loveruby.net>
* net/loveruby/cflat/asm/PeepholeOptimizer.java: unify insn
optimization and jump elimination.
* net/loveruby/cflat/utils/ClonableIterator.java -> Cursor.java
* net/loveruby/cflat/compiler/Options.java: use default
optimization rule set for -O.
Tue Sep 23 22:50:52 2008 Minero Aoki <aamine@loveruby.net> Tue Sep 23 22:50:52 2008 Minero Aoki <aamine@loveruby.net>
* net/loveruby/cflat/compiler/CodeGenerator.java: apply jump * net/loveruby/cflat/compiler/CodeGenerator.java: apply jump

View File

@ -1,26 +1,75 @@
package net.loveruby.cflat.asm; package net.loveruby.cflat.asm;
import net.loveruby.cflat.utils.ClonableIterator; import net.loveruby.cflat.utils.Cursor;
import java.util.*; import java.util.*;
public class PeepholeOptimizer implements AsmOptimizer { public class PeepholeOptimizer implements AsmOptimizer {
protected List filters; protected Map filterSet; // Map<String, List<Filter>>
public PeepholeOptimizer() { public PeepholeOptimizer() {
this.filters = defaultFilterSet(); this.filterSet = new HashMap();
}
public void add(Filter filter) {
String[] heads = filter.patternHeads();
for (int i = 0; i < heads.length; i++) {
String head = heads[i];
List list = (List)filterSet.get(head);
if (list == null) {
list = new ArrayList();
list.add(filter);
filterSet.put(head, list);
}
else {
list.add(filter);
}
}
} }
public List optimize(List assemblies) { public List optimize(List assemblies) {
return jumpElimination(insnOptimization(assemblies)); List result = new ArrayList();
Cursor cursor = new Cursor(assemblies);
while (cursor.hasNext()) {
Assembly asm = (Assembly)cursor.next();
if (asm.isInstruction()) {
Filter matched = matchFilter(cursor);
if (matched != null) {
matched.optimize(cursor, result);
continue;
}
}
result.add(asm);
}
return result;
} }
// List<Filter> protected Filter matchFilter(Cursor asms) {
protected List defaultFilterSet() { Instruction insn = (Instruction)asms.current();
List set = new ArrayList(); List filters = (List)filterSet.get(insn.mnemonic());
if (filters == null) return null;
if (filters.isEmpty()) return null;
Iterator it = filters.iterator();
while (it.hasNext()) {
Filter filter = (Filter)it.next();
if (filter.match(asms)) {
return filter;
}
}
return null;
}
static public PeepholeOptimizer defaultSet() {
PeepholeOptimizer set = new PeepholeOptimizer();
set.loadDefaultFilters();
return set;
}
protected void loadDefaultFilters() {
PeepholeOptimizer set = this;
// mov // mov
set.add(new Filter( set.add(new SingleInsnFilter(
new InsnPattern("mov", imm(0), reg()), new InsnPattern("mov", imm(0), reg()),
new InsnTemplate() { new InsnTransform() {
public Instruction apply(Instruction insn) { public Instruction apply(Instruction insn) {
return insn.build("xor", insn.operand2(), insn.operand2()); return insn.build("xor", insn.operand2(), insn.operand2());
} }
@ -28,21 +77,21 @@ public class PeepholeOptimizer implements AsmOptimizer {
)); ));
// add // add
set.add(new Filter( set.add(new SingleInsnFilter(
new InsnPattern("add", imm(-1), reg()), new InsnPattern("add", imm(-1), reg()),
new InsnTemplate() { new InsnTransform() {
public Instruction apply(Instruction insn) { public Instruction apply(Instruction insn) {
return insn.build("dec", insn.operand2()); return insn.build("dec", insn.operand2());
} }
} }
)); ));
set.add(new Filter( set.add(new SingleInsnFilter(
new InsnPattern("add", imm(0), reg()), new InsnPattern("add", imm(0), reg()),
null null
)); ));
set.add(new Filter( set.add(new SingleInsnFilter(
new InsnPattern("add", imm(1), reg()), new InsnPattern("add", imm(1), reg()),
new InsnTemplate() { new InsnTransform() {
public Instruction apply(Instruction insn) { public Instruction apply(Instruction insn) {
return insn.build("inc", insn.operand2()); return insn.build("inc", insn.operand2());
} }
@ -50,21 +99,21 @@ public class PeepholeOptimizer implements AsmOptimizer {
)); ));
// sub // sub
set.add(new Filter( set.add(new SingleInsnFilter(
new InsnPattern("sub", imm(-1), reg()), new InsnPattern("sub", imm(-1), reg()),
new InsnTemplate() { new InsnTransform() {
public Instruction apply(Instruction insn) { public Instruction apply(Instruction insn) {
return insn.build("inc", insn.operand2()); return insn.build("inc", insn.operand2());
} }
} }
)); ));
set.add(new Filter( set.add(new SingleInsnFilter(
new InsnPattern("sub", imm(0), reg()), new InsnPattern("sub", imm(0), reg()),
null null
)); ));
set.add(new Filter( set.add(new SingleInsnFilter(
new InsnPattern("sub", imm(1), reg()), new InsnPattern("sub", imm(1), reg()),
new InsnTemplate() { new InsnTransform() {
public Instruction apply(Instruction insn) { public Instruction apply(Instruction insn) {
return insn.build("dec", insn.operand2()); return insn.build("dec", insn.operand2());
} }
@ -72,52 +121,53 @@ public class PeepholeOptimizer implements AsmOptimizer {
)); ));
// imul // imul
set.add(new Filter( set.add(new SingleInsnFilter(
new InsnPattern("imul", imm(0), reg()), new InsnPattern("imul", imm(0), reg()),
new InsnTemplate() { new InsnTransform() {
public Instruction apply(Instruction insn) { public Instruction apply(Instruction insn) {
return insn.build("xorl", insn.operand2(), insn.operand2()); return insn.build("xorl", insn.operand2(), insn.operand2());
} }
} }
)); ));
set.add(new Filter( set.add(new SingleInsnFilter(
new InsnPattern("imul", imm(1), reg()), new InsnPattern("imul", imm(1), reg()),
null null
)); ));
set.add(new Filter( set.add(new SingleInsnFilter(
new InsnPattern("imul", imm(2), reg()), new InsnPattern("imul", imm(2), reg()),
new InsnTemplate() { new InsnTransform() {
public Instruction apply(Instruction insn) { public Instruction apply(Instruction insn) {
return insn.build("sal", imm(1), insn.operand2()); return insn.build("sal", imm(1), insn.operand2());
} }
} }
)); ));
set.add(new Filter( set.add(new SingleInsnFilter(
new InsnPattern("imul", imm(4), reg()), new InsnPattern("imul", imm(4), reg()),
new InsnTemplate() { new InsnTransform() {
public Instruction apply(Instruction insn) { public Instruction apply(Instruction insn) {
return insn.build("sal", imm(2), insn.operand2()); return insn.build("sal", imm(2), insn.operand2());
} }
} }
)); ));
set.add(new Filter( set.add(new SingleInsnFilter(
new InsnPattern("imul", imm(8), reg()), new InsnPattern("imul", imm(8), reg()),
new InsnTemplate() { new InsnTransform() {
public Instruction apply(Instruction insn) { public Instruction apply(Instruction insn) {
return insn.build("sal", imm(3), insn.operand2()); return insn.build("sal", imm(3), insn.operand2());
} }
} }
)); ));
set.add(new Filter( set.add(new SingleInsnFilter(
new InsnPattern("imul", imm(16), reg()), new InsnPattern("imul", imm(16), reg()),
new InsnTemplate() { new InsnTransform() {
public Instruction apply(Instruction insn) { public Instruction apply(Instruction insn) {
return insn.build("sal", imm(4), insn.operand2()); return insn.build("sal", imm(4), insn.operand2());
} }
} }
)); ));
return set; // jmp
set.add(new JumpEliminationFilter());
} }
protected ImmediateValue imm(long n) { protected ImmediateValue imm(long n) {
@ -128,57 +178,40 @@ public class PeepholeOptimizer implements AsmOptimizer {
return new AnyRegisterPattern(); return new AnyRegisterPattern();
} }
public List insnOptimization(List assemblies) { abstract class Filter {
List result = new ArrayList(); abstract public String[] patternHeads();
Iterator asms = assemblies.iterator(); abstract public boolean match(Cursor asms);
while (asms.hasNext()) { abstract public void optimize(Cursor src, List dest);
Assembly asm = (Assembly)asms.next();
if (! asm.isInstruction()) {
result.add(asm);
}
else {
Assembly optAsm = optimizeInstruction((Instruction)asm);
if (optAsm == null) {
// remove instruction
}
else {
result.add(optAsm);
}
}
}
return result;
} }
protected Assembly optimizeInstruction(Instruction insn) { //
Iterator it = filters.iterator(); // single instruction optimization
while (it.hasNext()) { //
Filter filter = (Filter)it.next();
if (filter.match(insn)) {
return filter.optimize(insn);
}
}
return insn;
}
class Filter { class SingleInsnFilter extends Filter {
protected InsnPattern pattern; protected InsnPattern pattern;
protected InsnTemplate template; protected InsnTransform transform;
public Filter(InsnPattern pattern, InsnTemplate template) { public SingleInsnFilter(InsnPattern pattern, InsnTransform transform) {
this.pattern = pattern; this.pattern = pattern;
this.template = template; this.transform = transform;
} }
public boolean match(Instruction insn) { /** Matching mnemonic of InstructionPattern */
return pattern.match(insn); public String[] patternHeads() {
return new String[] { pattern.name };
} }
public Instruction optimize(Instruction insn) { public boolean match(Cursor asms) {
if (template == null) { return pattern.match((Instruction)asms.current());
return null; }
public void optimize(Cursor src, List dest) {
if (transform == null) {
; // remove instruction
} }
else { else {
return template.apply(insn); dest.add(transform.apply((Instruction)src.current()));
} }
} }
} }
@ -207,7 +240,7 @@ public class PeepholeOptimizer implements AsmOptimizer {
} }
} }
interface InsnTemplate { interface InsnTransform {
abstract public Instruction apply(Instruction insn); abstract public Instruction apply(Instruction insn);
} }
@ -215,59 +248,60 @@ public class PeepholeOptimizer implements AsmOptimizer {
// jumpElimination // jumpElimination
// //
public List jumpElimination(List assemblies) { class JumpEliminationFilter extends Filter {
List result = new ArrayList(); public JumpEliminationFilter() {
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) { protected String[] jmpInsns() {
if (! asm.isInstruction()) return false; return new String[] { "jmp", "jz", "jne", "je", "jne" };
Instruction insn = (Instruction)asm; }
if (! insn.isJumpInstruction()) return false;
return doesLabelFollows(asms.dup(), insn.jmpDestination());
}
/** public String[] patternHeads() {
* Returns true if jmpDest is found in asms before any instruction return jmpInsns();
* or directives. For example, this method returns true if contents }
* of asms are:
* public void optimize(Cursor src, List dest) {
* if_end3: ; // remove jump
* # comment }
* jmpDest:
* mov public boolean match(Cursor asms) {
* mov Instruction insn = (Instruction)asms.current();
* add return doesLabelFollows(asms.dup(), insn.jmpDestination());
*/ }
protected boolean doesLabelFollows(ClonableIterator asms, Label jmpDest) {
while (asms.hasNext()) { /**
Assembly asm = (Assembly)asms.next(); * Returns true if jmpDest is found in asms before any instruction
if (asm.isLabel()) { * or directives. For example, this method returns true if contents
Label label = (Label)asm; * of asms are:
if (label.equals(jmpDest)) { *
return true; * if_end3:
* # comment
* jmpDest:
* mov
* mov
* add
*/
protected boolean doesLabelFollows(Cursor 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 { else if (asm.isComment()) {
continue; continue;
} }
else {
// instructions or directives
return false;
}
} }
else if (asm.isComment()) { return false;
continue;
}
else {
return false;
}
} }
return false;
} }
} }

View File

@ -119,7 +119,7 @@ class Options {
return new NullAsmOptimizer(); return new NullAsmOptimizer();
} }
else { else {
return new PeepholeOptimizer(); return PeepholeOptimizer.defaultSet();
} }
} }

View File

@ -1,25 +1,25 @@
package net.loveruby.cflat.utils; package net.loveruby.cflat.utils;
import java.util.*; import java.util.*;
public class ClonableIterator implements Iterator { public class Cursor implements Iterator {
protected List list; protected List list;
protected int index; protected int index;
public ClonableIterator(List list) { public Cursor(List list) {
this(list, 0); this(list, 0);
} }
protected ClonableIterator(List list, int index) { protected Cursor(List list, int index) {
this.list = list; this.list = list;
this.index = index; this.index = index;
} }
public Object clone() { public Object clone() {
return new ClonableIterator(list, index); return new Cursor(list, index);
} }
public ClonableIterator dup() { public Cursor dup() {
return new ClonableIterator(list, index); return new Cursor(list, index);
} }
public boolean hasNext() { public boolean hasNext() {
@ -30,11 +30,18 @@ public class ClonableIterator implements Iterator {
return list.get(index++); return list.get(index++);
} }
public Object current() {
if (index == 0) {
throw new Error("must not happen: Cursor#current");
}
return list.get(index - 1);
}
public void remove() { public void remove() {
list.remove(index); list.remove(index);
} }
public String toString() { public String toString() {
return "#<ClonableIterator list=" + list + " index=" + index + ">"; return "#<Cursor list=" + list + " index=" + index + ">";
} }
} }