Fix bug in liveness analysis when running on non-SSA IR

This commit is contained in:
Alexey Andreev 2019-08-13 11:37:21 +03:00
parent 1d19562c49
commit 67c86b089f
6 changed files with 60 additions and 22 deletions

View File

@ -68,12 +68,15 @@ public class Optimizer {
public void optimize(AsyncMethodNode method, AsyncProgramSplitter splitter, boolean friendlyToDebugger) {
LivenessAnalyzer liveness = new LivenessAnalyzer();
liveness.analyze(splitter.getOriginalProgram());
liveness.analyze(splitter.getOriginalProgram(), method.getReference().getDescriptor());
Graph cfg = ProgramUtils.buildControlFlowGraph(splitter.getOriginalProgram());
boolean[] preservedVars = new boolean[method.getVariables().size()];
for (int i = 0; i < splitter.size(); ++i) {
findEscapingLiveVars(liveness, cfg, splitter, i, preservedVars);
}
for (int i = 0; i < splitter.size(); ++i) {
boolean[] preservedVars = new boolean[method.getVariables().size()];
ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size());
stats.analyze(splitter.getProgram(i));
applyParametersToWriteStats(stats, method.getReference());
@ -81,7 +84,6 @@ public class Optimizer {
AsyncMethodPart part = method.getBody().get(i);
BreakEliminator breakEliminator = new BreakEliminator();
breakEliminator.eliminate(part.getStatement());
findEscapingLiveVars(liveness, cfg, splitter, i, preservedVars);
OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.writes, stats.reads,
stats.constants, friendlyToDebugger);
part.getStatement().acceptVisitor(optimizer);

View File

@ -112,7 +112,7 @@ public class CoroutineTransformation {
parameterCount = methodReference.parameterCount();
returnType = methodReference.getReturnType();
variableTypes.inferTypes(program, methodReference);
livenessAnalysis.analyze(program);
livenessAnalysis.analyze(program, methodReference.getDescriptor());
splitter = new BasicBlockSplitter(program);
int basicBlockCount = program.basicBlockCount();
createSplitPrologue();

View File

@ -36,6 +36,7 @@ import org.teavm.model.BasicBlock;
import org.teavm.model.FieldReference;
import org.teavm.model.Incoming;
import org.teavm.model.Instruction;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference;
import org.teavm.model.Phi;
import org.teavm.model.Program;
@ -95,7 +96,7 @@ public class EscapeAnalysis {
escapingVars[definitionClasses[i]] = true;
}
}
analyzePhis(program);
analyzePhis(program, methodReference.getDescriptor());
propagateFields(program, visitor.fields);
fields = packFields(visitor.fields);
@ -114,9 +115,9 @@ public class EscapeAnalysis {
return varFields != null ? varFields.clone() : null;
}
private void analyzePhis(Program program) {
private void analyzePhis(Program program, MethodDescriptor methodDescriptor) {
LivenessAnalyzer livenessAnalyzer = new LivenessAnalyzer();
livenessAnalyzer.analyze(program);
livenessAnalyzer.analyze(program, methodDescriptor);
GraphBuilder graphBuilder = new GraphBuilder(program.variableCount());
IntDeque queue = new IntArrayDeque();

View File

@ -134,7 +134,7 @@ public class GCShadowStackContributor {
List<Map<Instruction, BitSet>> liveInInformation = new ArrayList<>();
LivenessAnalyzer livenessAnalyzer = new LivenessAnalyzer();
livenessAnalyzer.analyze(program);
livenessAnalyzer.analyze(program, method.getDescriptor());
DefinitionExtractor defExtractor = new DefinitionExtractor();
UsageExtractor useExtractor = new UsageExtractor();

View File

@ -18,6 +18,7 @@ package org.teavm.model.util;
import com.carrotsearch.hppc.IntHashSet;
import com.carrotsearch.hppc.IntSet;
import com.carrotsearch.hppc.IntStack;
import java.util.Arrays;
import java.util.BitSet;
import org.teavm.common.DominatorTree;
import org.teavm.common.Graph;
@ -25,6 +26,7 @@ import org.teavm.common.GraphUtils;
import org.teavm.model.BasicBlock;
import org.teavm.model.Incoming;
import org.teavm.model.Instruction;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.Phi;
import org.teavm.model.Program;
import org.teavm.model.Variable;
@ -45,7 +47,11 @@ public class LivenessAnalyzer {
return (BitSet) liveOutVars[block].clone();
}
public void analyze(Program program) {
public void analyze(Program program, MethodDescriptor descriptor) {
analyze(program, descriptor.parameterCount() + 1);
}
public void analyze(Program program, int parameterCount) {
Graph cfg = ProgramUtils.buildControlFlowGraph(program);
DominatorTree dominatorTree = GraphUtils.buildDominatorTree(cfg);
liveVars = new BitSet[program.basicBlockCount()];
@ -58,32 +64,28 @@ public class LivenessAnalyzer {
UsageExtractor usageExtractor = new UsageExtractor();
DefinitionExtractor defExtractor = new DefinitionExtractor();
IntStack stack = new IntStack();
int[] definitions = new int[program.variableCount()];
IntSet[] definitionsBuilder = new IntSet[program.variableCount()];
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
if (block.getExceptionVariable() != null) {
definitions[block.getExceptionVariable().getIndex()] = i;
addDefinition(definitionsBuilder, block.getExceptionVariable().getIndex(), i);
}
for (Instruction insn : block) {
insn.acceptVisitor(usageExtractor);
IntSet usedVars = new IntHashSet();
for (Variable var : usageExtractor.getUsedVariables()) {
stack.push(i);
stack.push(var.getIndex());
usedVars.add(var.getIndex());
}
insn.acceptVisitor(defExtractor);
for (Variable var : defExtractor.getDefinedVariables()) {
if (!usedVars.contains(var.getIndex())) {
definitions[var.getIndex()] = i;
}
addDefinition(definitionsBuilder, var.getIndex(), i);
}
}
for (Phi phi : block.getPhis()) {
definitions[phi.getReceiver().getIndex()] = i;
addDefinition(definitionsBuilder, phi.getReceiver().getIndex(), i);
for (Incoming incoming : phi.getIncomings()) {
stack.push(incoming.getSource().getIndex());
stack.push(incoming.getValue().getIndex());
@ -91,15 +93,39 @@ public class LivenessAnalyzer {
}
}
while (!stack.isEmpty()) {
int[][] definitions = new int[program.variableCount()][];
for (int i = 0; i < definitions.length; ++i) {
IntSet definitionsByVar = definitionsBuilder[i];
if (definitionsByVar == null) {
definitions[i] = new int[0];
} else {
definitions[i] = definitionsByVar.toArray();
Arrays.sort(definitions[i]);
}
}
worklist: while (!stack.isEmpty()) {
int variable = stack.pop();
int block = stack.pop();
BitSet blockLiveVars = liveVars[block];
if (blockLiveVars.get(variable) || definitions[variable] == block
|| !dominatorTree.dominates(definitions[variable], block)) {
if (blockLiveVars.get(variable)) {
continue;
}
liveVars[block].set(variable, true);
boolean hasDominatingDefinition = variable < parameterCount;
for (int definedAt : definitions[variable]) {
if (definedAt == block) {
continue worklist;
}
if (!hasDominatingDefinition && dominatorTree.dominates(definedAt, block)) {
hasDominatingDefinition = true;
}
}
if (!hasDominatingDefinition) {
continue;
}
blockLiveVars.set(variable, true);
for (int pred : cfg.incomingEdges(block)) {
stack.push(pred);
stack.push(variable);
@ -118,4 +144,13 @@ public class LivenessAnalyzer {
}
}
}
private static void addDefinition(IntSet[] definitions, int v, int block) {
IntSet definitionsByVar = definitions[v];
if (definitionsByVar == null) {
definitionsByVar = new IntHashSet();
definitions[v] = definitionsByVar;
}
definitionsByVar.add(block);
}
}

View File

@ -42,7 +42,7 @@ public class RegisterAllocator {
insertPhiArgumentsCopies(program);
InterferenceGraphBuilder interferenceBuilder = new InterferenceGraphBuilder();
LivenessAnalyzer liveness = new LivenessAnalyzer();
liveness.analyze(program);
liveness.analyze(program, method.getDescriptor());
List<MutableGraphNode> interferenceGraph = interferenceBuilder.build(
program, method.parameterCount(), liveness);
DisjointSet congruenceClasses = buildPhiCongruenceClasses(program);