mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-08 07:54:11 -08:00
Make SSA and non-SSA liveness analyses. Fix aliasing local variable names with special variables.
Fix #416
This commit is contained in:
parent
6307a67f8f
commit
97f9967153
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user