Make SSA and non-SSA liveness analyses. Fix aliasing local variable names with special variables.

Fix #416
This commit is contained in:
Alexey Andreev 2019-08-14 12:40:58 +03:00
parent 6307a67f8f
commit 97f9967153
4 changed files with 210 additions and 55 deletions

View File

@ -27,7 +27,7 @@ import org.teavm.model.Program;
import org.teavm.model.Variable;
import org.teavm.model.util.AsyncProgramSplitter;
import org.teavm.model.util.DefinitionExtractor;
import org.teavm.model.util.LivenessAnalyzer;
import org.teavm.model.util.NonSsaLivenessAnalyzer;
import org.teavm.model.util.ProgramUtils;
import org.teavm.model.util.UsageExtractor;
@ -67,7 +67,7 @@ public class Optimizer {
}
public void optimize(AsyncMethodNode method, AsyncProgramSplitter splitter, boolean friendlyToDebugger) {
LivenessAnalyzer liveness = new LivenessAnalyzer();
NonSsaLivenessAnalyzer liveness = new NonSsaLivenessAnalyzer();
liveness.analyze(splitter.getOriginalProgram(), method.getReference().getDescriptor());
Graph cfg = ProgramUtils.buildControlFlowGraph(splitter.getOriginalProgram());
@ -114,7 +114,7 @@ public class Optimizer {
}
}
private void findEscapingLiveVars(LivenessAnalyzer liveness, Graph cfg, AsyncProgramSplitter splitter,
private void findEscapingLiveVars(NonSsaLivenessAnalyzer liveness, Graph cfg, AsyncProgramSplitter splitter,
int partIndex, boolean[] output) {
Program originalProgram = splitter.getOriginalProgram();
Program program = splitter.getProgram(partIndex);

View File

@ -112,6 +112,11 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
this.minifying = context.isMinifying();
this.naming = context.getNaming();
this.debugEmitter = context.getDebugEmitter();
if (!minifying) {
usedVariableNames.add("$tmp");
usedVariableNames.add("$ptr");
usedVariableNames.add("$thread");
}
}
public boolean isLongLibraryUsed() {

View File

@ -15,10 +15,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;
@ -54,81 +51,85 @@ public class LivenessAnalyzer {
public void analyze(Program program, int parameterCount) {
Graph cfg = ProgramUtils.buildControlFlowGraph(program);
DominatorTree dominatorTree = GraphUtils.buildDominatorTree(cfg);
BitSet[] visited = new BitSet[program.basicBlockCount()];
liveVars = new BitSet[program.basicBlockCount()];
liveOutVars = new BitSet[program.basicBlockCount()];
for (int i = 0; i < liveVars.length; ++i) {
liveVars[i] = new BitSet(program.basicBlockCount());
liveOutVars[i] = new BitSet(program.basicBlockCount());
visited[i] = new BitSet(program.variableCount());
liveVars[i] = new BitSet(program.variableCount());
liveOutVars[i] = new BitSet(program.variableCount());
}
UsageExtractor usageExtractor = new UsageExtractor();
DefinitionExtractor defExtractor = new DefinitionExtractor();
IntStack stack = new IntStack();
IntSet[] definitionsBuilder = new IntSet[program.variableCount()];
int[] definitions = new int[program.variableCount()];
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
if (block.getExceptionVariable() != null) {
addDefinition(definitionsBuilder, block.getExceptionVariable().getIndex(), i);
}
BitSet usedVariables = new BitSet(program.variableCount());
for (Instruction insn : block) {
insn.acceptVisitor(usageExtractor);
for (Variable var : usageExtractor.getUsedVariables()) {
stack.push(i);
stack.push(var.getIndex());
}
for (Instruction insn = block.getLastInstruction(); insn != null; insn = insn.getPrevious()) {
insn.acceptVisitor(defExtractor);
for (Variable var : defExtractor.getDefinedVariables()) {
addDefinition(definitionsBuilder, var.getIndex(), i);
definitions[var.getIndex()] = i;
usedVariables.clear(var.getIndex());
}
insn.acceptVisitor(usageExtractor);
for (Variable var : usageExtractor.getUsedVariables()) {
usedVariables.set(var.getIndex());
}
}
for (Phi phi : block.getPhis()) {
addDefinition(definitionsBuilder, phi.getReceiver().getIndex(), i);
definitions[phi.getReceiver().getIndex()] = i;
usedVariables.clear(phi.getReceiver().getIndex());
for (Incoming incoming : phi.getIncomings()) {
stack.push(incoming.getSource().getIndex());
stack.push(incoming.getValue().getIndex());
}
}
}
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]);
if (block.getExceptionVariable() != null) {
definitions[block.getExceptionVariable().getIndex()] = i;
usedVariables.clear(block.getExceptionVariable().getIndex());
}
if (i == 0) {
for (int v = 0; v < parameterCount; ++v) {
definitions[v] = 0;
usedVariables.clear(v);
}
}
int[] predecessors = cfg.incomingEdges(i);
for (int v = usedVariables.nextSetBit(0); v >= 0; v = usedVariables.nextSetBit(v + 1)) {
liveVars[i].set(v);
for (int pred : predecessors) {
stack.push(pred);
stack.push(v);
}
}
}
worklist: while (!stack.isEmpty()) {
while (!stack.isEmpty()) {
int variable = stack.pop();
int block = stack.pop();
BitSet blockLiveVars = liveVars[block];
if (blockLiveVars.get(variable)) {
BitSet blockVisited = visited[block];
if (blockVisited.get(variable)) {
continue;
}
blockVisited.set(variable);
boolean hasDominatingDefinition = variable < parameterCount;
for (int definedAt : definitions[variable]) {
if (definedAt == block) {
continue worklist;
}
if (!hasDominatingDefinition && dominatorTree.dominates(definedAt, block)) {
hasDominatingDefinition = true;
}
}
if (!hasDominatingDefinition) {
if (definitions[variable] == block || !dominatorTree.dominates(definitions[variable], block)) {
continue;
}
blockLiveVars.set(variable, true);
liveVars[block].set(variable, true);
for (int pred : cfg.incomingEdges(block)) {
stack.push(pred);
stack.push(variable);
if (!visited[pred].get(variable)) {
stack.push(pred);
stack.push(variable);
}
}
}
@ -144,13 +145,4 @@ 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

@ -0,0 +1,158 @@
/*
* Copyright 2019 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.model.util;
import com.carrotsearch.hppc.IntStack;
import java.util.BitSet;
import org.teavm.common.Graph;
import org.teavm.model.BasicBlock;
import org.teavm.model.Instruction;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.Program;
import org.teavm.model.Variable;
public class NonSsaLivenessAnalyzer {
private BitSet[] liveVars;
private BitSet[] liveOutVars;
public boolean liveIn(int block, int var) {
return liveVars[block].get(var);
}
public BitSet liveIn(int block) {
return (BitSet) liveVars[block].clone();
}
public BitSet liveOut(int block) {
return (BitSet) liveOutVars[block].clone();
}
public void analyze(Program program, MethodDescriptor descriptor) {
analyze(program, descriptor.parameterCount() + 1);
}
public void analyze(Program program, int parameterCount) {
Graph cfg = ProgramUtils.buildControlFlowGraph(program);
BitSet[] definitions = new BitSet[program.basicBlockCount()];
BitSet[] definedVars = new BitSet[program.basicBlockCount()];
BitSet[] visited = new BitSet[program.basicBlockCount()];
liveVars = new BitSet[program.basicBlockCount()];
liveOutVars = new BitSet[program.basicBlockCount()];
for (int i = 0; i < liveVars.length; ++i) {
definitions[i] = new BitSet(program.variableCount());
definedVars[i] = new BitSet(program.variableCount());
visited[i] = new BitSet(program.variableCount());
liveVars[i] = new BitSet(program.variableCount());
liveOutVars[i] = new BitSet(program.variableCount());
}
UsageExtractor usageExtractor = new UsageExtractor();
DefinitionExtractor defExtractor = new DefinitionExtractor();
IntStack stack = new IntStack();
IntStack defStack = new IntStack();
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
BitSet usedVariables = new BitSet();
BitSet definedVariables = definitions[i];
for (Instruction insn = block.getLastInstruction(); insn != null; insn = insn.getPrevious()) {
insn.acceptVisitor(defExtractor);
for (Variable var : defExtractor.getDefinedVariables()) {
definedVariables.set(var.getIndex());
usedVariables.clear(var.getIndex());
}
insn.acceptVisitor(usageExtractor);
for (Variable var : usageExtractor.getUsedVariables()) {
usedVariables.set(var.getIndex());
}
}
assert block.getPhis().isEmpty();
if (block.getExceptionVariable() != null) {
definedVariables.set(block.getExceptionVariable().getIndex());
usedVariables.clear(block.getExceptionVariable().getIndex());
}
if (i == 0) {
for (int v = 0; v < parameterCount; ++v) {
definedVariables.set(v);
usedVariables.clear(v);
}
}
for (int v = usedVariables.nextSetBit(0); v >= 0; v = usedVariables.nextSetBit(v + 1)) {
liveVars[i].set(v);
visited[i].set(v);
for (int pred : cfg.incomingEdges(i)) {
stack.push(pred);
stack.push(v);
}
}
for (int v = definedVariables.nextSetBit(0); v >= 0; v = definedVariables.nextSetBit(v + 1)) {
defStack.push(i);
defStack.push(v);
}
}
while (!defStack.isEmpty()) {
int variable = defStack.pop();
int block = defStack.pop();
BitSet blockDefinedVars = definedVars[block];
if (blockDefinedVars.get(variable)) {
continue;
}
blockDefinedVars.set(variable);
for (int succ : cfg.outgoingEdges(block)) {
if (!definedVars[succ].get(variable)) {
defStack.push(succ);
defStack.push(variable);
}
}
}
while (!stack.isEmpty()) {
int variable = stack.pop();
int block = stack.pop();
BitSet blockVisited = visited[block];
if (blockVisited.get(variable)) {
continue;
}
blockVisited.set(variable);
if (definitions[block].get(variable) || !definedVars[block].get(variable)) {
continue;
}
liveVars[block].set(variable);
for (int pred : cfg.incomingEdges(block)) {
if (!visited[pred].get(variable)) {
stack.push(pred);
stack.push(variable);
}
}
}
for (int i = 0; i < liveVars.length; ++i) {
for (int j : cfg.incomingEdges(i)) {
liveOutVars[j].or(liveVars[i]);
}
}
}
}