Skip to content

Commit

Permalink
More compiler optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
mirkosertic committed May 8, 2024
1 parent 20b9bf7 commit 4d72ef1
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,44 +25,11 @@
import de.mirkosertic.bytecoder.core.ir.Variable;
import de.mirkosertic.bytecoder.core.parser.CompileUnit;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Stack;

public class CopyToRedundantVariable implements Optimizer {

private List<Node> evaluationOrderOf(final Node node) {
final List<Node> result = new ArrayList<>();

// We do a DFS here
final Set<Node> visited = new HashSet<>();
final Stack<Node> workingQueue = new Stack<>();

for (int i = node.incomingDataFlows.length - 1; i >= 0; i--) {
workingQueue.push(node.incomingDataFlows[i]);
}
visited.add(node);

while (!workingQueue.isEmpty()) {
final Node workingItem = workingQueue.pop();
if (visited.add(workingItem)) {
if (!(workingItem instanceof ControlTokenConsumer)) {
if (workingItem.hasSideSideEffect() || workingItem.nodeType == NodeType.Variable) {
result.add(workingItem);
} else {
for (int i = workingItem.incomingDataFlows.length - 1; i >= 0; i--) {
workingQueue.push(workingItem.incomingDataFlows[i]);
}
}
}
}
}

return result;
}

@Override
public boolean optimize(final BackendType backendType, final CompileUnit compileUnit, final ResolvedMethod method) {

Expand Down Expand Up @@ -91,7 +58,7 @@ public boolean optimize(final BackendType backendType, final CompileUnit compile
if (variableToCheck.incomingDataFlows.length == 1 && variableToCheck.outgoingDataFlows().length == 1) {
final ControlTokenConsumer successor = workingItem.controlFlowsTo.values().stream().findFirst().get();

final List<Node> evaluationOrder = evaluationOrderOf(successor);
final List<Node> evaluationOrder = Utils.evaluationOrderOf(successor);

if (!evaluationOrder.isEmpty() && evaluationOrder.get(evaluationOrder.size() - 1) == variableToCheck) {
// We found a candidate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class InefficientSetFieldOrArray implements Optimizer {

@Override
public boolean optimize(final BackendType backendType, final CompileUnit compileUnit, final ResolvedMethod method) {

final Graph g = method.methodBody;
boolean changed = false;
for (final Copy copy : g.nodes().stream().filter(t -> t.nodeType == NodeType.Copy).map(t -> (Copy) t).collect(Collectors.toList())) {
Expand All @@ -44,7 +45,7 @@ public boolean optimize(final BackendType backendType, final CompileUnit compile
final Node source = copy.incomingDataFlows[0];
// Case one : there is something written to the copyTarget
final Node[] succOutgoing = successor.outgoingDataFlows();
if (source.nodeType == NodeType.Variable && copyTarget.incomingDataFlows.length == 2 && copyTarget.incomingDataFlows[0] == copy && copyTarget.incomingDataFlows[1] == successor && succOutgoing.length == 1 && succOutgoing[0] == copyTarget) {
if (source.nodeType == NodeType.Variable && copyTarget.incomingDataFlows.length == 2 && copyTarget.incomingDataFlows[0] == copy && copyTarget.incomingDataFlows[1] == successor && succOutgoing.length == 1 && succOutgoing[0] == copyTarget && !Utils.evaluationOrderOf(successor).contains(copyTarget)) {

copyTarget.removeFromIncomingData(copy);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package de.mirkosertic.bytecoder.core.optimizer;

import de.mirkosertic.bytecoder.core.backend.BackendType;
import de.mirkosertic.bytecoder.core.ir.Copy;
import de.mirkosertic.bytecoder.core.ir.Graph;
import de.mirkosertic.bytecoder.core.ir.ResolvedField;
import de.mirkosertic.bytecoder.core.ir.ResolvedMethod;
import de.mirkosertic.bytecoder.core.ir.SetInstanceField;
import de.mirkosertic.bytecoder.core.ir.StandardProjections;
import de.mirkosertic.bytecoder.core.ir.Variable;
import de.mirkosertic.bytecoder.core.parser.CompileUnit;
import de.mirkosertic.bytecoder.core.patternmatcher.Match;
import de.mirkosertic.bytecoder.core.patternmatcher.PatternMatcher;
import org.objectweb.asm.Type;

public class InefficientSetFieldWithPatternMatcher implements Optimizer {

@Override
public boolean optimize(final BackendType backendType, final CompileUnit compileUnit, final ResolvedMethod method) {

final Graph patternToSearch = new Graph(compileUnit.getLogger());
final Variable source = patternToSearch.newVariable(Type.INT_TYPE);
final Variable target = patternToSearch.newVariable(Type.INT_TYPE);
final Copy cp1 = patternToSearch.newCopy();
cp1.addIncomingData(source);
final SetInstanceField sif = patternToSearch.newSetInstanceField(new ResolvedField(null, "field", null, null, 0));
target.addIncomingData(cp1, sif);
cp1.addControlFlowTo(StandardProjections.DEFAULT, sif);

final PatternMatcher matcher = new PatternMatcher(compileUnit.getLogger(), sif);
for (final Match match : matcher.findMatches(method.methodBody)) {
final Variable sourceMatch = match.mappingFor(source);
final Copy copyMatch = match.mappingFor(cp1);
final SetInstanceField sifMatch = match.mappingFor(sif);
final Variable targetMatch = match.mappingFor(target);

sourceMatch.addIncomingData(sifMatch);
copyMatch.deleteFromControlFlow();
method.methodBody.deleteNode(targetMatch);

return true;
}

return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ public enum Optimizations implements Optimizer {
new DropUnusedValues(),
new CopyToUnusedPHIOrVariable(),
new SingularPHIOrVariable(),
//new InefficientSetFieldOrArray(),
new InefficientSetFieldOrArray(),
//new InefficientSetField()
}),
ALL(new Optimizer[] {
new DropDebugData(),
Expand All @@ -53,7 +54,8 @@ public enum Optimizations implements Optimizer {
new DropUnusedValues(),
new CopyToUnusedPHIOrVariable(),
new SingularPHIOrVariable(),
//new InefficientSetFieldOrArray(),
new InefficientSetFieldOrArray(),
//new InefficientSetField()
}),
;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,8 @@
JBox2D JS Opt4 1699546 bytes
LUA Wasm Opt4 443106 bytes
LUA JS Opt4 1519864 bytes

JBox2D Wasm Opt4 472281 bytes
JBox2D JS Opt4 1691486 bytes
LUA Wasm Opt4 441364 bytes
LUA JS Opt4 1516822 bytes
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,17 @@
*/
package de.mirkosertic.bytecoder.core.optimizer;

import de.mirkosertic.bytecoder.core.ir.ControlTokenConsumer;
import de.mirkosertic.bytecoder.core.ir.Node;
import de.mirkosertic.bytecoder.core.ir.NodeType;
import de.mirkosertic.bytecoder.core.ir.ResolvedMethod;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Stack;

public class Utils {

public static boolean isVariableOrConstant(final Node n) {
Expand Down Expand Up @@ -47,6 +54,36 @@ public static long methodSize(final ResolvedMethod rm) {
t.nodeType == NodeType.If).count();
}

public static List<Node> evaluationOrderOf(final Node node) {
final List<Node> result = new ArrayList<>();

// We do a DFS here
final Set<Node> visited = new HashSet<>();
final Stack<Node> workingQueue = new Stack<>();

for (int i = node.incomingDataFlows.length - 1; i >= 0; i--) {
workingQueue.push(node.incomingDataFlows[i]);
}
visited.add(node);

while (!workingQueue.isEmpty()) {
final Node workingItem = workingQueue.pop();
if (visited.add(workingItem)) {
if (!(workingItem instanceof ControlTokenConsumer)) {
if (workingItem.hasSideSideEffect() || workingItem.nodeType == NodeType.Variable) {
result.add(workingItem);
} else {
for (int i = workingItem.incomingDataFlows.length - 1; i >= 0; i--) {
workingQueue.push(workingItem.incomingDataFlows[i]);
}
}
}
}
}

return result;
}

public static int maxInlineSourceSize() {
return Integer.parseInt(System.getProperty("bytecoder.maxInlineSourceSize", "20"));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public Node root() {
return root;
}

public Node mappingFor(final Node node) {
return mappings.get(node);
public <T extends Node> T mappingFor(final T node) {
return (T) mappings.get(node);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,17 @@ private Node parseOutgoingData(final String token, final Node currentNode, final

return node;

} else if (candidates.size() > 1) {
// More than one candidate, maybe we can further strip this down
final List<Node> furtherCheck = candidates.stream().filter(t -> evaluationContext.nodeKnownAt(expectedNodeIndex) && t == evaluationContext.getNodeAt(expectedNodeIndex)).collect(Collectors.toList());
if (furtherCheck.size() == 1) {
return furtherCheck.get(0);
} else {
PatternMatcher.this.logger.debug(" -> Failed, cannot strip down nodes {} to {}", candidates, token);
return null;
}
}

PatternMatcher.this.logger.debug(" -> Failed, matching outgoing nodes are != 1 : {}", candidates);
return null;
}
Expand Down
20 changes: 12 additions & 8 deletions core/src/test/java/de/mirkosertic/bytecoder/IRExport.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import de.mirkosertic.bytecoder.core.ir.Graph;
import de.mirkosertic.bytecoder.core.ir.ResolvedMethod;
import de.mirkosertic.bytecoder.core.loader.BytecoderLoader;
import de.mirkosertic.bytecoder.core.optimizer.InefficientSetFieldWithPatternMatcher;
import de.mirkosertic.bytecoder.core.optimizer.Optimizations;
import de.mirkosertic.bytecoder.core.parser.CompileUnit;
import de.mirkosertic.bytecoder.core.parser.Loader;
Expand All @@ -31,15 +32,15 @@ public static void doit(final String[] args) {
public int dosomething(final int value) {
//doit(new String[0]);
//final IRExport dummy = new IRExport();
assert value > 10;
int x = value;
for (int i = 0; i < 100; i++) {
x = x + i + value;
}
//assert value > 10;
//int x = value;
//for (int i = 0; i < 100; i++) {
// x = x + i + value;
// }
IRExport t = new IRExport();
t.target = x;
t.target2 = x + 1;
return x;
t.target = value;
t.target2 = value + 1;
return value;
}

public static void main(final String[] args) throws IOException, ClassNotFoundException {
Expand Down Expand Up @@ -76,6 +77,9 @@ public static void main(final String[] args) throws IOException, ClassNotFoundEx
while (Optimizations.ALL.optimize(BackendType.JS, compileUnit, method)) {
}

while (new InefficientSetFieldWithPatternMatcher().optimize(BackendType.JS, compileUnit, method)) {
}

try (final FileOutputStream fos = new FileOutputStream("debug_optimized.dot")) {
g.writeDebugTo(fos);
}
Expand Down

0 comments on commit 4d72ef1

Please sign in to comment.