Keep variable names in generated sources

This commit is contained in:
Alexey Andreev 2016-08-27 16:50:14 +03:00
parent ef5145d6fd
commit cc9af93021
9 changed files with 145 additions and 82 deletions

View File

@ -60,6 +60,10 @@ class UnusedVariableEliminator extends RecursiveVisitor {
indexes[variables[var]] = index;
reorderedVariables.add(variableNodes[var]);
}
VariableNode node = variableNodes[var];
if (node.getName() != null) {
reorderedVariables.get(index).setName(node.getName());
}
return index;
}

View File

@ -137,10 +137,25 @@ public class WasmCRenderer {
}
private void renderFunction(WasmFunction function) {
line(functionDeclaration(function) + " {");
WasmCRenderingVisitor visitor = new WasmCRenderingVisitor(function.getResult(),
function.getLocalVariables().size(), function.getModule());
StringBuilder declaration = new StringBuilder();
renderFunctionModifiers(declaration, function);
declaration.append(WasmCRenderingVisitor.mapType(function.getResult())).append(' ');
declaration.append(function.getName()).append('(');
for (int i = 0; i < function.getParameters().size(); ++i) {
if (i > 0) {
declaration.append(", ");
}
declaration.append(WasmCRenderingVisitor.mapType(function.getParameters().get(i)));
WasmLocal var = function.getLocalVariables().get(i);
declaration.append(' ').append(visitor.getVariableName(var));
}
declaration.append(") {");
line(declaration.toString());
indent();
WasmCRenderingVisitor visitor = new WasmCRenderingVisitor(function.getResult(), function.getModule());
List<WasmLocal> variables = function.getLocalVariables().subList(function.getParameters().size(),
function.getLocalVariables().size());
for (WasmLocal variable : variables) {
@ -175,29 +190,28 @@ public class WasmCRenderer {
private String functionDeclaration(WasmFunction function) {
StringBuilder sb = new StringBuilder();
if (function.getImportName() != null) {
sb.append("extern ");
} else if (function.getExportName() == null) {
sb.append("static ");
}
renderFunctionModifiers(sb, function);
sb.append(WasmCRenderingVisitor.mapType(function.getResult())).append(' ');
sb.append(function.getName()).append("(");
WasmCRenderingVisitor visitor = new WasmCRenderingVisitor(function.getResult(), function.getModule());
for (int i = 0; i < function.getParameters().size(); ++i) {
if (i > 0) {
sb.append(", ");
}
sb.append(WasmCRenderingVisitor.mapType(function.getParameters().get(i)));
WasmLocal local = i < function.getLocalVariables().size()
? function.getLocalVariables().get(i)
: null;
sb.append(" ").append(local != null ? visitor.getVariableName(local) : "var_" + i);
}
sb.append(")");
return sb.toString();
}
private static void renderFunctionModifiers(StringBuilder sb, WasmFunction function) {
if (function.getImportName() != null) {
sb.append("extern ");
} else if (function.getExportName() == null) {
sb.append("static ");
}
}
@Override
public String toString() {
return out.toString();

View File

@ -18,8 +18,10 @@ package org.teavm.backend.wasm.render;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.teavm.backend.wasm.model.WasmFunction;
import org.teavm.backend.wasm.model.WasmLocal;
import org.teavm.backend.wasm.model.WasmModule;
@ -67,8 +69,11 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
private int blockIndex;
private WasmType functionType;
private WasmModule module;
private String[] localVariableNames;
private Set<String> usedVariableNames = new HashSet<>();
WasmCRenderingVisitor(WasmType functionType, WasmModule module) {
WasmCRenderingVisitor(WasmType functionType, int variableCount, WasmModule module) {
localVariableNames = new String[variableCount];
this.functionType = functionType;
this.module = module;
}
@ -1036,9 +1041,23 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
}
String getVariableName(WasmLocal local) {
if (local.getName() != null) {
return local.getName();
String result = localVariableNames[local.getIndex()];
if (result == null) {
if (local.getName() != null) {
result = local.getName();
} else {
result = "localVar" + local.getIndex();
}
if (!usedVariableNames.add(result)) {
String base = result;
int suffix = 1;
while (!usedVariableNames.add(base + suffix)) {
++suffix;
}
result = base + suffix;
}
localVariableNames[local.getIndex()] = result;
}
return "var_" + local.getIndex();
return result;
}
}

View File

@ -37,7 +37,7 @@ public class PreOptimizingClassHolderSource implements ClassHolderSource {
return null;
}
for (MethodHolder method : cls.getMethods()) {
new GlobalValueNumbering().optimize(method, method.getProgram());
new GlobalValueNumbering(true).optimize(method, method.getProgram());
new UnusedVariableElimination().optimize(method, method.getProgram());
}
cache.put(name, cls);

View File

@ -34,12 +34,17 @@ public class GlobalValueNumbering implements MethodOptimization {
private Program program;
private int currentBlockIndex;
private DominatorTree domTree;
private boolean namesPreserved;
private static class KnownValue {
int value;
int location;
}
public GlobalValueNumbering(boolean namesPreserved) {
this.namesPreserved = namesPreserved;
}
@Override
public boolean optimize(MethodReader method, Program program) {
boolean affected = false;
@ -66,28 +71,6 @@ public class GlobalValueNumbering implements MethodOptimization {
int v = stack[--top];
currentBlockIndex = v;
BasicBlock block = program.basicBlockAt(v);
/*for (int i = 0; i < block.getPhis().size(); ++i) {
Phi phi = block.getPhis().get(i);
int sharedValue = -2;
for (Incoming incoming : phi.getIncomings()) {
int value = map[incoming.getValue().getIndex()];
incoming.setValue(program.variableAt(value));
if (sharedValue != -2 && sharedValue != incoming.getValue().getIndex()) {
sharedValue = -1;
} else {
sharedValue = incoming.getValue().getIndex();
}
}
if (sharedValue != -1) {
if (sharedValue != -2) {
AssignInstruction assignInsn = new AssignInstruction();
assignInsn.setReceiver(phi.getReceiver());
assignInsn.setAssignee(program.variableAt(sharedValue));
block.getInstructions().add(0, assignInsn);
}
block.getPhis().remove(i--);
}
}*/
if (block.getExceptionVariable() != null) {
int var = map[block.getExceptionVariable().getIndex()];
@ -149,21 +132,9 @@ public class GlobalValueNumbering implements MethodOptimization {
stack[top++] = succ;
}
}
String[] debugNames = new String[program.variableCount()];
for (int i = 0; i < program.variableCount(); ++i) {
debugNames[i] = program.variableAt(i).getDebugName();
program.variableAt(i).setDebugName(null);
}
for (int i = 0; i < map.length; ++i) {
if (map[i] != i) {
Variable mapVar = program.variableAt(map[i]);
if (debugNames[i] != null && mapVar.getDebugName() == null) {
mapVar.setDebugName(debugNames[i]);
}
program.deleteVariable(i);
} else {
program.variableAt(i).setDebugName(debugNames[i]);
}
}
@ -174,19 +145,38 @@ public class GlobalValueNumbering implements MethodOptimization {
private void bind(int var, String value) {
String name = program.variableAt(map[var]).getDebugName();
if (name == null) {
if (name == null || namesPreserved) {
name = "";
}
KnownValue known = knownValues.get(name + ":" + value);
if (known != null && domTree.dominates(known.location, currentBlockIndex) && known.value != var) {
if (known == null) {
known = knownValues.get(":" + value);
}
boolean namesCompatible = !namesPreserved;
if (!namesCompatible && known != null) {
String knownName = program.variableAt(known.value).getDebugName();
if (knownName == null) {
knownName = "";
}
namesCompatible = knownName.isEmpty() || name.isEmpty() || knownName.equals(name);
}
if (known != null && domTree.dominates(known.location, currentBlockIndex) && known.value != var
&& namesCompatible) {
eliminate = true;
map[var] = known.value;
if (!name.isEmpty()) {
program.variableAt(known.value).setDebugName(name);
knownValues.put(name + ":" + value, known);
}
} else {
known = new KnownValue();
known.location = currentBlockIndex;
known.value = var;
knownValues.put(name + ":" + value, known);
if (!name.isEmpty()) {
knownValues.put(":" + value, known);
}
}
}
@ -498,6 +488,16 @@ public class GlobalValueNumbering implements MethodOptimization {
@Override
public void visit(AssignInstruction insn) {
if (namesPreserved) {
if (insn.getReceiver().getDebugName() != null && insn.getAssignee().getDebugName() != null) {
if (!insn.getAssignee().getDebugName().equals(insn.getReceiver().getDebugName())) {
return;
}
}
}
if (insn.getReceiver().getDebugName() != null) {
insn.getAssignee().setDebugName(insn.getReceiver().getDebugName());
}
map[insn.getReceiver().getIndex()] = map[insn.getAssignee().getIndex()];
eliminate = true;
}

View File

@ -15,6 +15,7 @@
*/
package org.teavm.model.util;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import org.teavm.common.IntegerArray;
@ -23,11 +24,12 @@ import org.teavm.common.MutableGraphNode;
class GraphColorer {
public void colorize(List<MutableGraphNode> graph, int[] colors) {
colorize(graph, colors, new int[graph.size()]);
colorize(graph, colors, new int[graph.size()], new String[graph.size()]);
}
public void colorize(List<MutableGraphNode> graph, int[] colors, int[] categories) {
public void colorize(List<MutableGraphNode> graph, int[] colors, int[] categories, String[] names) {
IntegerArray colorCategories = new IntegerArray(graph.size());
List<String> colorNames = new ArrayList<>();
for (int i = 0; i < colors.length; ++i) {
int color = colors[i];
if (colors[i] < 0) {
@ -36,7 +38,11 @@ class GraphColorer {
while (colorCategories.size() <= color) {
colorCategories.add(-1);
}
while (colorNames.size() <= color) {
colorNames.add(null);
}
colorCategories.set(color, categories[i]);
colorNames.set(color, names[i]);
}
BitSet usedColors = new BitSet();
for (int v : getOrdering(graph)) {
@ -56,11 +62,19 @@ class GraphColorer {
color = usedColors.nextClearBit(color);
while (colorCategories.size() <= color) {
colorCategories.add(-1);
colorNames.add(null);
}
int category = colorCategories.get(color);
if (category < 0 || category == categories[v]) {
String name = colorNames.get(color);
if ((category < 0 || category == categories[v])
&& (name == null || names[v] == null || name.equals(names[v]))) {
colors[v] = color;
colorCategories.set(color, categories[v]);
if (names[v] != null) {
colorNames.set(color, names[v]);
} else {
names[v] = name;
}
break;
}
++color;

View File

@ -67,13 +67,33 @@ public class RegisterAllocator {
maxClass = Math.max(maxClass, cls + 1);
}
int[] categories = getVariableCategories(program, method.getReference());
String[] names = getVariableNames(program);
int[] classCategories = new int[maxClass];
String[] classNames = new String[maxClass];
for (int i = 0; i < categories.length; ++i) {
classCategories[classArray[i]] = categories[i];
classNames[classArray[i]] = names[i];
}
colorer.colorize(interferenceGraph, colors, classCategories);
colorer.colorize(interferenceGraph, colors, classCategories, classNames);
int maxColor = 0;
for (int i = 0; i < colors.length; ++i) {
program.variableAt(i).setRegister(colors[i]);
maxColor = Math.max(maxClass, colors[i]);
}
String[] namesByRegister = new String[maxColor];
for (int i = 0; i < colors.length; ++i) {
Variable var = program.variableAt(i);
if (var.getDebugName() != null && var.getRegister() >= 0) {
namesByRegister[var.getRegister()] = var.getDebugName();
}
}
for (int i = 0; i < colors.length; ++i) {
Variable var = program.variableAt(i);
if (var.getRegister() >= 0) {
var.setDebugName(namesByRegister[var.getRegister()]);
}
}
for (int i = 0; i < program.basicBlockCount(); ++i) {
@ -95,6 +115,14 @@ public class RegisterAllocator {
return categories;
}
private String[] getVariableNames(ProgramReader program) {
String[] names = new String[program.variableCount()];
for (int i = 0; i < names.length; ++i) {
names[i] = program.variableAt(i).getDebugName();
}
return names;
}
private static void joinClassNodes(List<MutableGraphNode> graph, DisjointSet classes) {
int sz = graph.size();
for (int i = 0; i < sz; ++i) {
@ -257,13 +285,15 @@ public class RegisterAllocator {
BasicBlock block = program.basicBlockAt(i);
mapper.apply(block);
}
String[] originalNames = new String[program.variableCount()];
String[] originalNames = getVariableNames(program);
for (int i = 0; i < program.variableCount(); ++i) {
Variable var = program.variableAt(i);
originalNames[i] = var.getDebugName();
program.variableAt(i).setDebugName(null);
}
for (int i = 0; i < program.variableCount(); ++i) {
program.variableAt(varMap[i]).setDebugName(originalNames[i]);
Variable var = program.variableAt(varMap[i]);
if (originalNames[i] != null) {
var.setDebugName(originalNames[i]);
}
}
}

View File

@ -375,7 +375,6 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
}
}
removeDebugNames(classSet);
optimize(classSet);
if (wasCancelled()) {
return;
@ -451,25 +450,6 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
}
}
private void removeDebugNames(ListableClassHolderSource classes) {
if (optimizationLevel == TeaVMOptimizationLevel.SIMPLE) {
return;
}
for (String className : classes.getClassNames()) {
ClassHolder cls = classes.get(className);
for (MethodHolder method : cls.getMethods()) {
if (method.getProgram() != null) {
for (int i = 0; i < method.getProgram().variableCount(); ++i) {
method.getProgram().variableAt(i).setDebugName(null);
}
}
}
if (wasCancelled()) {
return;
}
}
}
private void optimize(ListableClassHolderSource classSource) {
for (String className : classSource.getClassNames()) {
ClassHolder cls = classSource.get(className);
@ -521,7 +501,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
optimizations.add(new LoopInversion());
optimizations.add(new LoopInvariantMotion());
}
optimizations.add(new GlobalValueNumbering());
optimizations.add(new GlobalValueNumbering(optimizationLevel == TeaVMOptimizationLevel.SIMPLE));
if (optimizationLevel.ordinal() >= TeaVMOptimizationLevel.ADVANCED.ordinal()) {
optimizations.add(new ConstantConditionElimination());
optimizations.add(new RedundantJumpElimination());

View File

@ -64,6 +64,8 @@ public final class TeaVMRunner {
.create("m"));
options.addOption(OptionBuilder
.withDescription("optimization level (1-3)")
.hasArg()
.withArgName("number")
.create("O"));
options.addOption(OptionBuilder
.withArgName("separate|merge|none")