mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-09 08:24:10 -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.Variable;
|
||||||
import org.teavm.model.util.AsyncProgramSplitter;
|
import org.teavm.model.util.AsyncProgramSplitter;
|
||||||
import org.teavm.model.util.DefinitionExtractor;
|
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.ProgramUtils;
|
||||||
import org.teavm.model.util.UsageExtractor;
|
import org.teavm.model.util.UsageExtractor;
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ public class Optimizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void optimize(AsyncMethodNode method, AsyncProgramSplitter splitter, boolean friendlyToDebugger) {
|
public void optimize(AsyncMethodNode method, AsyncProgramSplitter splitter, boolean friendlyToDebugger) {
|
||||||
LivenessAnalyzer liveness = new LivenessAnalyzer();
|
NonSsaLivenessAnalyzer liveness = new NonSsaLivenessAnalyzer();
|
||||||
liveness.analyze(splitter.getOriginalProgram(), method.getReference().getDescriptor());
|
liveness.analyze(splitter.getOriginalProgram(), method.getReference().getDescriptor());
|
||||||
|
|
||||||
Graph cfg = ProgramUtils.buildControlFlowGraph(splitter.getOriginalProgram());
|
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) {
|
int partIndex, boolean[] output) {
|
||||||
Program originalProgram = splitter.getOriginalProgram();
|
Program originalProgram = splitter.getOriginalProgram();
|
||||||
Program program = splitter.getProgram(partIndex);
|
Program program = splitter.getProgram(partIndex);
|
||||||
|
|
|
@ -112,6 +112,11 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||||
this.minifying = context.isMinifying();
|
this.minifying = context.isMinifying();
|
||||||
this.naming = context.getNaming();
|
this.naming = context.getNaming();
|
||||||
this.debugEmitter = context.getDebugEmitter();
|
this.debugEmitter = context.getDebugEmitter();
|
||||||
|
if (!minifying) {
|
||||||
|
usedVariableNames.add("$tmp");
|
||||||
|
usedVariableNames.add("$ptr");
|
||||||
|
usedVariableNames.add("$thread");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLongLibraryUsed() {
|
public boolean isLongLibraryUsed() {
|
||||||
|
|
|
@ -15,10 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.model.util;
|
package org.teavm.model.util;
|
||||||
|
|
||||||
import com.carrotsearch.hppc.IntHashSet;
|
|
||||||
import com.carrotsearch.hppc.IntSet;
|
|
||||||
import com.carrotsearch.hppc.IntStack;
|
import com.carrotsearch.hppc.IntStack;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
import org.teavm.common.DominatorTree;
|
import org.teavm.common.DominatorTree;
|
||||||
import org.teavm.common.Graph;
|
import org.teavm.common.Graph;
|
||||||
|
@ -54,83 +51,87 @@ public class LivenessAnalyzer {
|
||||||
public void analyze(Program program, int parameterCount) {
|
public void analyze(Program program, int parameterCount) {
|
||||||
Graph cfg = ProgramUtils.buildControlFlowGraph(program);
|
Graph cfg = ProgramUtils.buildControlFlowGraph(program);
|
||||||
DominatorTree dominatorTree = GraphUtils.buildDominatorTree(cfg);
|
DominatorTree dominatorTree = GraphUtils.buildDominatorTree(cfg);
|
||||||
|
BitSet[] visited = new BitSet[program.basicBlockCount()];
|
||||||
liveVars = new BitSet[program.basicBlockCount()];
|
liveVars = new BitSet[program.basicBlockCount()];
|
||||||
liveOutVars = new BitSet[program.basicBlockCount()];
|
liveOutVars = new BitSet[program.basicBlockCount()];
|
||||||
for (int i = 0; i < liveVars.length; ++i) {
|
for (int i = 0; i < liveVars.length; ++i) {
|
||||||
liveVars[i] = new BitSet(program.basicBlockCount());
|
visited[i] = new BitSet(program.variableCount());
|
||||||
liveOutVars[i] = new BitSet(program.basicBlockCount());
|
liveVars[i] = new BitSet(program.variableCount());
|
||||||
|
liveOutVars[i] = new BitSet(program.variableCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
UsageExtractor usageExtractor = new UsageExtractor();
|
UsageExtractor usageExtractor = new UsageExtractor();
|
||||||
DefinitionExtractor defExtractor = new DefinitionExtractor();
|
DefinitionExtractor defExtractor = new DefinitionExtractor();
|
||||||
IntStack stack = new IntStack();
|
IntStack stack = new IntStack();
|
||||||
IntSet[] definitionsBuilder = new IntSet[program.variableCount()];
|
int[] definitions = new int[program.variableCount()];
|
||||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||||
BasicBlock block = program.basicBlockAt(i);
|
BasicBlock block = program.basicBlockAt(i);
|
||||||
|
|
||||||
if (block.getExceptionVariable() != null) {
|
BitSet usedVariables = new BitSet(program.variableCount());
|
||||||
addDefinition(definitionsBuilder, block.getExceptionVariable().getIndex(), i);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Instruction insn : block) {
|
for (Instruction insn = block.getLastInstruction(); insn != null; insn = insn.getPrevious()) {
|
||||||
insn.acceptVisitor(usageExtractor);
|
|
||||||
for (Variable var : usageExtractor.getUsedVariables()) {
|
|
||||||
stack.push(i);
|
|
||||||
stack.push(var.getIndex());
|
|
||||||
}
|
|
||||||
insn.acceptVisitor(defExtractor);
|
insn.acceptVisitor(defExtractor);
|
||||||
for (Variable var : defExtractor.getDefinedVariables()) {
|
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()) {
|
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()) {
|
for (Incoming incoming : phi.getIncomings()) {
|
||||||
stack.push(incoming.getSource().getIndex());
|
stack.push(incoming.getSource().getIndex());
|
||||||
stack.push(incoming.getValue().getIndex());
|
stack.push(incoming.getValue().getIndex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (block.getExceptionVariable() != null) {
|
||||||
|
definitions[block.getExceptionVariable().getIndex()] = i;
|
||||||
|
usedVariables.clear(block.getExceptionVariable().getIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
int[][] definitions = new int[program.variableCount()][];
|
if (i == 0) {
|
||||||
for (int i = 0; i < definitions.length; ++i) {
|
for (int v = 0; v < parameterCount; ++v) {
|
||||||
IntSet definitionsByVar = definitionsBuilder[i];
|
definitions[v] = 0;
|
||||||
if (definitionsByVar == null) {
|
usedVariables.clear(v);
|
||||||
definitions[i] = new int[0];
|
|
||||||
} else {
|
|
||||||
definitions[i] = definitionsByVar.toArray();
|
|
||||||
Arrays.sort(definitions[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
worklist: while (!stack.isEmpty()) {
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!stack.isEmpty()) {
|
||||||
int variable = stack.pop();
|
int variable = stack.pop();
|
||||||
int block = stack.pop();
|
int block = stack.pop();
|
||||||
BitSet blockLiveVars = liveVars[block];
|
BitSet blockVisited = visited[block];
|
||||||
if (blockLiveVars.get(variable)) {
|
if (blockVisited.get(variable)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
blockVisited.set(variable);
|
||||||
|
|
||||||
boolean hasDominatingDefinition = variable < parameterCount;
|
if (definitions[variable] == block || !dominatorTree.dominates(definitions[variable], block)) {
|
||||||
for (int definedAt : definitions[variable]) {
|
|
||||||
if (definedAt == block) {
|
|
||||||
continue worklist;
|
|
||||||
}
|
|
||||||
if (!hasDominatingDefinition && dominatorTree.dominates(definedAt, block)) {
|
|
||||||
hasDominatingDefinition = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!hasDominatingDefinition) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
liveVars[block].set(variable, true);
|
||||||
blockLiveVars.set(variable, true);
|
|
||||||
for (int pred : cfg.incomingEdges(block)) {
|
for (int pred : cfg.incomingEdges(block)) {
|
||||||
|
if (!visited[pred].get(variable)) {
|
||||||
stack.push(pred);
|
stack.push(pred);
|
||||||
stack.push(variable);
|
stack.push(variable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < liveVars.length; ++i) {
|
for (int i = 0; i < liveVars.length; ++i) {
|
||||||
for (int j : cfg.incomingEdges(i)) {
|
for (int j : cfg.incomingEdges(i)) {
|
||||||
|
@ -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