mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-08 07:54:11 -08:00
Add tests for escape analysis/scalar replacement. Fix found bugs
This commit is contained in:
parent
e4fab2be41
commit
d3bed47b1d
|
@ -19,19 +19,20 @@ import com.carrotsearch.hppc.IntArrayDeque;
|
|||
import com.carrotsearch.hppc.IntDeque;
|
||||
import com.carrotsearch.hppc.IntOpenHashSet;
|
||||
import com.carrotsearch.hppc.IntSet;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import org.teavm.common.DisjointSet;
|
||||
import org.teavm.common.Graph;
|
||||
import org.teavm.common.GraphBuilder;
|
||||
import org.teavm.model.BasicBlock;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.FieldReader;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.Incoming;
|
||||
import org.teavm.model.Instruction;
|
||||
|
@ -39,6 +40,7 @@ import org.teavm.model.MethodReference;
|
|||
import org.teavm.model.Phi;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.model.TryCatchBlock;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.Variable;
|
||||
import org.teavm.model.instructions.AbstractInstructionVisitor;
|
||||
import org.teavm.model.instructions.AssignInstruction;
|
||||
|
@ -47,7 +49,6 @@ import org.teavm.model.instructions.BranchingInstruction;
|
|||
import org.teavm.model.instructions.CastInstruction;
|
||||
import org.teavm.model.instructions.ClassConstantInstruction;
|
||||
import org.teavm.model.instructions.CloneArrayInstruction;
|
||||
import org.teavm.model.instructions.ConstructInstruction;
|
||||
import org.teavm.model.instructions.ExitInstruction;
|
||||
import org.teavm.model.instructions.GetElementInstruction;
|
||||
import org.teavm.model.instructions.GetFieldInstruction;
|
||||
|
@ -67,17 +68,13 @@ import org.teavm.model.util.LivenessAnalyzer;
|
|||
import org.teavm.model.util.UsageExtractor;
|
||||
|
||||
public class EscapeAnalysis {
|
||||
private ClassReaderSource classSource;
|
||||
private int[] definitionClasses;
|
||||
private boolean[] escapingVars;
|
||||
private FieldReference[][] fields;
|
||||
|
||||
public EscapeAnalysis(ClassReaderSource classSource) {
|
||||
this.classSource = classSource;
|
||||
}
|
||||
private Map<FieldReference, ValueType> fieldTypes;
|
||||
|
||||
public void analyze(Program program, MethodReference methodReference) {
|
||||
InstructionEscapeVisitor visitor = new InstructionEscapeVisitor(program.variableCount(), classSource);
|
||||
InstructionEscapeVisitor visitor = new InstructionEscapeVisitor(program.variableCount());
|
||||
for (int i = 0; i <= methodReference.parameterCount(); ++i) {
|
||||
visitor.escapingVars[i] = true;
|
||||
}
|
||||
|
@ -91,9 +88,9 @@ public class EscapeAnalysis {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
definitionClasses = visitor.definitionClasses.pack(program.variableCount());
|
||||
escapingVars = new boolean[program.variableCount()];
|
||||
fieldTypes = visitor.fieldTypes;
|
||||
for (int i = 0; i < program.variableCount(); ++i) {
|
||||
if (visitor.escapingVars[i]) {
|
||||
escapingVars[definitionClasses[i]] = true;
|
||||
|
@ -101,6 +98,7 @@ public class EscapeAnalysis {
|
|||
}
|
||||
analyzePhis(program);
|
||||
|
||||
propagateFields(program, visitor.fields);
|
||||
fields = packFields(visitor.fields);
|
||||
}
|
||||
|
||||
|
@ -108,6 +106,10 @@ public class EscapeAnalysis {
|
|||
return escapingVars[definitionClasses[var]];
|
||||
}
|
||||
|
||||
public ValueType getFieldType(FieldReference field) {
|
||||
return fieldTypes.get(field);
|
||||
}
|
||||
|
||||
public FieldReference[] getFields(int var) {
|
||||
FieldReference[] varFields = fields[definitionClasses[var]];
|
||||
return varFields != null ? varFields.clone() : null;
|
||||
|
@ -123,10 +125,13 @@ public class EscapeAnalysis {
|
|||
IntSet sharedIncomingVars = new IntOpenHashSet();
|
||||
BitSet usedVars = getUsedVarsInBlock(livenessAnalyzer, block);
|
||||
for (Phi phi : block.getPhis()) {
|
||||
if (escapes(phi.getReceiver().getIndex())) {
|
||||
queue.addLast(phi.getReceiver().getIndex());
|
||||
}
|
||||
for (Incoming incoming : phi.getIncomings()) {
|
||||
int var = incoming.getValue().getIndex();
|
||||
graphBuilder.addEdge(var, phi.getReceiver().getIndex());
|
||||
if (escapingVars[definitionClasses[var]] || !sharedIncomingVars.add(var) || usedVars.get(var)) {
|
||||
if (escapes(var) || !sharedIncomingVars.add(var) || usedVars.get(var)) {
|
||||
queue.addLast(var);
|
||||
}
|
||||
}
|
||||
|
@ -142,6 +147,9 @@ public class EscapeAnalysis {
|
|||
for (int successor : graph.outgoingEdges(var)) {
|
||||
queue.addLast(successor);
|
||||
}
|
||||
for (int predecessor : graph.incomingEdges(var)) {
|
||||
queue.addLast(predecessor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -167,6 +175,52 @@ public class EscapeAnalysis {
|
|||
return usedVars;
|
||||
}
|
||||
|
||||
private void propagateFields(Program program, List<Set<FieldReference>> fields) {
|
||||
class Task {
|
||||
int index;
|
||||
FieldReference field;
|
||||
Task(int index, FieldReference field) {
|
||||
this.index = index;
|
||||
this.field = field;
|
||||
}
|
||||
}
|
||||
Queue<Task> queue = new ArrayDeque<>();
|
||||
|
||||
GraphBuilder graphBuilder = new GraphBuilder(program.variableCount());
|
||||
for (BasicBlock block : program.getBasicBlocks()) {
|
||||
for (Phi phi : block.getPhis()) {
|
||||
for (Incoming incoming : phi.getIncomings()) {
|
||||
graphBuilder.addEdge(phi.getReceiver().getIndex(), incoming.getValue().getIndex());
|
||||
Set<FieldReference> receiverFields = fields.get(phi.getReceiver().getIndex());
|
||||
if (receiverFields != null) {
|
||||
for (FieldReference field : receiverFields) {
|
||||
queue.add(new Task(phi.getReceiver().getIndex(), field));
|
||||
}
|
||||
receiverFields.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Graph graph = graphBuilder.build();
|
||||
|
||||
while (!queue.isEmpty()) {
|
||||
Task task = queue.remove();
|
||||
|
||||
Set<FieldReference> taskFields = fields.get(task.index);
|
||||
if (taskFields == null) {
|
||||
taskFields = new LinkedHashSet<>();
|
||||
fields.set(task.index, taskFields);
|
||||
}
|
||||
if (!taskFields.add(task.field)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int successor : graph.outgoingEdges(task.index)) {
|
||||
queue.add(new Task(successor, task.field));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private FieldReference[][] packFields(List<Set<FieldReference>> fields) {
|
||||
List<Set<FieldReference>> joinedFields = new ArrayList<>(Collections.nCopies(fields.size(), null));
|
||||
|
||||
|
@ -193,13 +247,12 @@ public class EscapeAnalysis {
|
|||
}
|
||||
|
||||
private static class InstructionEscapeVisitor extends AbstractInstructionVisitor {
|
||||
ClassReaderSource classSource;
|
||||
DisjointSet definitionClasses;
|
||||
boolean[] escapingVars;
|
||||
List<Set<FieldReference>> fields;
|
||||
Map<FieldReference, ValueType> fieldTypes = new HashMap<>();
|
||||
|
||||
public InstructionEscapeVisitor(int variableCount, ClassReaderSource classSource) {
|
||||
this.classSource = classSource;
|
||||
public InstructionEscapeVisitor(int variableCount) {
|
||||
fields = new ArrayList<>(Collections.nCopies(variableCount, null));
|
||||
definitionClasses = new DisjointSet();
|
||||
for (int i = 0; i < variableCount; ++i) {
|
||||
|
@ -208,21 +261,6 @@ public class EscapeAnalysis {
|
|||
escapingVars = new boolean[variableCount];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ConstructInstruction insn) {
|
||||
ClassReader cls = classSource.get(insn.getType());
|
||||
if (cls == null) {
|
||||
escapingVars[insn.getReceiver().getIndex()] = true;
|
||||
}
|
||||
|
||||
while (cls != null) {
|
||||
for (FieldReader field : cls.getFields()) {
|
||||
addField(insn.getReceiver(), field.getReference());
|
||||
}
|
||||
cls = cls.getParent() != null ? classSource.get(cls.getParent()) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NullConstantInstruction insn) {
|
||||
escapingVars[insn.getReceiver().getIndex()] = true;
|
||||
|
@ -275,16 +313,16 @@ public class EscapeAnalysis {
|
|||
@Override
|
||||
public void visit(GetFieldInstruction insn) {
|
||||
escapingVars[insn.getReceiver().getIndex()] = true;
|
||||
addField(insn.getInstance(), insn.getField());
|
||||
addField(insn.getInstance(), insn.getField(), insn.getFieldType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(PutFieldInstruction insn) {
|
||||
escapingVars[insn.getValue().getIndex()] = true;
|
||||
addField(insn.getInstance(), insn.getField());
|
||||
addField(insn.getInstance(), insn.getField(), insn.getFieldType());
|
||||
}
|
||||
|
||||
private void addField(Variable instance, FieldReference field) {
|
||||
private void addField(Variable instance, FieldReference field, ValueType fieldType) {
|
||||
if (instance == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -294,6 +332,7 @@ public class EscapeAnalysis {
|
|||
fields.set(instance.getIndex(), fieldSet);
|
||||
}
|
||||
fieldSet.add(field);
|
||||
fieldTypes.put(field, fieldType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -21,8 +21,6 @@ import java.util.LinkedHashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.teavm.model.BasicBlock;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.FieldReader;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.Incoming;
|
||||
import org.teavm.model.Instruction;
|
||||
|
@ -59,15 +57,23 @@ public class ScalarReplacement implements MethodOptimization {
|
|||
Collections.nCopies(program.variableCount(), null));
|
||||
|
||||
MethodReference methodReference = context.getMethod().getReference();
|
||||
EscapeAnalysis escapeAnalysis = new EscapeAnalysis(context.getClassSource());
|
||||
EscapeAnalysis escapeAnalysis = new EscapeAnalysis();
|
||||
escapeAnalysis.analyze(program, methodReference);
|
||||
boolean canPerform = false;
|
||||
for (int i = 0; i < fieldMappings.size(); ++i) {
|
||||
FieldReference[] fields = escapeAnalysis.getFields(i);
|
||||
if (!escapeAnalysis.escapes(i) && fields != null) {
|
||||
Variable instanceVar = program.variableAt(i);
|
||||
Map<FieldReference, Variable> fieldMapping = new LinkedHashMap<>();
|
||||
for (FieldReference field : fields) {
|
||||
fieldMapping.put(field, program.createVariable());
|
||||
Variable var = program.createVariable();
|
||||
if (instanceVar.getDebugName() != null) {
|
||||
var.setDebugName(instanceVar.getDebugName() + "$" + field.getFieldName());
|
||||
}
|
||||
if (instanceVar.getLabel() != null) {
|
||||
var.setLabel(instanceVar.getLabel() + "$" + field.getFieldName());
|
||||
}
|
||||
fieldMapping.put(field, var);
|
||||
}
|
||||
fieldMappings.set(i, fieldMapping);
|
||||
canPerform = true;
|
||||
|
@ -77,8 +83,7 @@ public class ScalarReplacement implements MethodOptimization {
|
|||
return false;
|
||||
}
|
||||
|
||||
ScalarReplacementVisitor visitor = new ScalarReplacementVisitor(escapeAnalysis, context.getClassSource(),
|
||||
fieldMappings);
|
||||
ScalarReplacementVisitor visitor = new ScalarReplacementVisitor(escapeAnalysis, fieldMappings);
|
||||
for (BasicBlock block : program.getBasicBlocks()) {
|
||||
for (Instruction instruction : block) {
|
||||
instruction.acceptVisitor(visitor);
|
||||
|
@ -116,7 +121,7 @@ public class ScalarReplacement implements MethodOptimization {
|
|||
phiReplacement.getIncomings().add(incomingReplacement);
|
||||
}
|
||||
|
||||
additionalPhis.add(phi);
|
||||
additionalPhis.add(phiReplacement);
|
||||
}
|
||||
block.getPhis().remove(i--);
|
||||
}
|
||||
|
@ -134,13 +139,11 @@ public class ScalarReplacement implements MethodOptimization {
|
|||
|
||||
static class ScalarReplacementVisitor extends AbstractInstructionVisitor {
|
||||
private EscapeAnalysis escapeAnalysis;
|
||||
private ClassReaderSource classSource;
|
||||
private List<Map<FieldReference, Variable>> fieldMappings;
|
||||
|
||||
public ScalarReplacementVisitor(EscapeAnalysis escapeAnalysis, ClassReaderSource classSource,
|
||||
public ScalarReplacementVisitor(EscapeAnalysis escapeAnalysis,
|
||||
List<Map<FieldReference, Variable>> fieldMappings) {
|
||||
this.escapeAnalysis = escapeAnalysis;
|
||||
this.classSource = classSource;
|
||||
this.fieldMappings = fieldMappings;
|
||||
}
|
||||
|
||||
|
@ -149,9 +152,9 @@ public class ScalarReplacement implements MethodOptimization {
|
|||
int var = insn.getReceiver().getIndex();
|
||||
if (!escapeAnalysis.escapes(var) && escapeAnalysis.getFields(var) != null) {
|
||||
for (FieldReference fieldRef : escapeAnalysis.getFields(var)) {
|
||||
FieldReader field = classSource.resolve(fieldRef);
|
||||
ValueType fieldType = escapeAnalysis.getFieldType(fieldRef);
|
||||
Variable receiver = fieldMappings.get(insn.getReceiver().getIndex()).get(fieldRef);
|
||||
Instruction initializer = generateDefaultValue(field.getType(), receiver);
|
||||
Instruction initializer = generateDefaultValue(fieldType, receiver);
|
||||
initializer.setLocation(initializer.getLocation());
|
||||
insn.insertPrevious(initializer);
|
||||
}
|
||||
|
|
|
@ -318,7 +318,7 @@ class ListingLexer {
|
|||
if (c < ' ') {
|
||||
throw new ListingParseException("Unexpected character in string literal: " + c, index);
|
||||
}
|
||||
sb.append(c);
|
||||
sb.append((char) c);
|
||||
nextChar();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -235,12 +235,9 @@ public class PhiUpdater {
|
|||
|
||||
int[] successors = domGraph.outgoingEdges(index);
|
||||
|
||||
IntSet successorSet = IntOpenHashSet.from(successors);
|
||||
for (Incoming output : phiOutputs.get(index)) {
|
||||
if (successorSet.contains(output.getPhi().getBasicBlock().getIndex())) {
|
||||
Variable var = output.getValue();
|
||||
output.setValue(use(var));
|
||||
}
|
||||
Variable var = output.getValue();
|
||||
output.setValue(use(var));
|
||||
}
|
||||
|
||||
for (int j = successors.length - 1; j >= 0; --j) {
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright 2017 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.optimization.test;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
import org.teavm.dependency.DependencyInfo;
|
||||
import org.teavm.model.ClassHolder;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.ListingParseUtils;
|
||||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.optimization.MethodOptimizationContext;
|
||||
import org.teavm.model.optimization.ScalarReplacement;
|
||||
import org.teavm.model.text.ListingBuilder;
|
||||
import org.teavm.model.util.ProgramUtils;
|
||||
|
||||
public class ScalarReplacementTest {
|
||||
private static final String PREFIX = "model/optimization/scalar-replacement/";
|
||||
@Rule
|
||||
public TestName name = new TestName();
|
||||
|
||||
@Test
|
||||
public void simple() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void phi() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void escapingPhi() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void escapingPhiSource() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void escapingPhiReceiver() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void escapingSharedPhiSource() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copy() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
String originalPath = PREFIX + name.getMethodName() + ".original.txt";
|
||||
String expectedPath = PREFIX + name.getMethodName() + ".expected.txt";
|
||||
Program original = ListingParseUtils.parseFromResource(originalPath);
|
||||
Program expected = ListingParseUtils.parseFromResource(expectedPath);
|
||||
|
||||
performScalarReplacement(original);
|
||||
|
||||
String originalText = new ListingBuilder().buildListing(original, "");
|
||||
String expectedText = new ListingBuilder().buildListing(expected, "");
|
||||
Assert.assertEquals(expectedText, originalText);
|
||||
}
|
||||
|
||||
private void performScalarReplacement(Program program) {
|
||||
ClassHolder testClass = new ClassHolder("TestClass");
|
||||
MethodHolder testMethod = new MethodHolder("testMethod", ValueType.VOID);
|
||||
testMethod.setProgram(ProgramUtils.copy(program));
|
||||
testClass.addMethod(testMethod);
|
||||
|
||||
MethodOptimizationContext context = new MethodOptimizationContext() {
|
||||
@Override
|
||||
public MethodReader getMethod() {
|
||||
return testMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DependencyInfo getDependencyInfo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassReaderSource getClassSource() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
new ScalarReplacement().optimize(context, program);
|
||||
}
|
||||
}
|
|
@ -50,6 +50,11 @@ public class PhiUpdaterTest {
|
|||
doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void phiIncoming() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
String originalPath = PREFIX + name.getMethodName() + ".original.txt";
|
||||
String expectedPath = PREFIX + name.getMethodName() + ".expected.txt";
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
var @this as this
|
||||
|
||||
$start
|
||||
@a$foo := 0
|
||||
@a$bar := 0
|
||||
@tmp1 := 23
|
||||
@a$foo_1 := @tmp1
|
||||
@b$foo := @a$foo_1
|
||||
@b$bar := @a$bar
|
||||
@tmp2 := 42
|
||||
@b$bar_1 := @tmp2
|
||||
@r := @b$foo
|
||||
@s := @b$bar_1
|
||||
@t := @a$bar
|
||||
return @r
|
|
@ -0,0 +1,13 @@
|
|||
var @this as this
|
||||
|
||||
$start
|
||||
@a := new A
|
||||
@tmp1 := 23
|
||||
field A.foo @a := @tmp1 as I
|
||||
@b := @a
|
||||
@tmp2 := 42
|
||||
field A.bar @b := @tmp2 as I
|
||||
@r := field A.foo @b as I
|
||||
@s := field A.bar @b as I
|
||||
@t := field A.bar @a as I
|
||||
return @r
|
|
@ -0,0 +1,23 @@
|
|||
var @this as this
|
||||
|
||||
$start
|
||||
@cond := invokeStatic `Foo.bar()I`
|
||||
if @cond == 0 then goto $zero else goto $nonzero
|
||||
$zero
|
||||
@a := new A
|
||||
@tmp1 := null
|
||||
field A.foo @a := @tmp1 as `Ljava/lang/Object;`
|
||||
goto $joint
|
||||
$nonzero
|
||||
@b := new B
|
||||
@tmp2 := 23
|
||||
field B.bar @b := @tmp2 as I
|
||||
field B.boo @b := @tmp2 as I
|
||||
goto $joint
|
||||
$joint
|
||||
@c := phi @a from $zero, @b from $nonzero
|
||||
@tmp3 := 12.0F
|
||||
field C.baz @c := @tmp3 as F
|
||||
@r := field B.bar @c as I
|
||||
@s := field B.bar @b as I
|
||||
return @r
|
|
@ -0,0 +1,23 @@
|
|||
var @this as this
|
||||
|
||||
$start
|
||||
@cond := invokeStatic `Foo.bar()I`
|
||||
if @cond == 0 then goto $zero else goto $nonzero
|
||||
$zero
|
||||
@a := new A
|
||||
@tmp1 := null
|
||||
field A.foo @a := @tmp1 as `Ljava/lang/Object;`
|
||||
goto $joint
|
||||
$nonzero
|
||||
@b := new B
|
||||
@tmp2 := 23
|
||||
field B.bar @b := @tmp2 as I
|
||||
field B.boo @b := @tmp2 as I
|
||||
goto $joint
|
||||
$joint
|
||||
@c := phi @a from $zero, @b from $nonzero
|
||||
@tmp3 := 12.0F
|
||||
field C.baz @c := @tmp3 as F
|
||||
@r := field B.bar @c as I
|
||||
@s := field B.bar @b as I
|
||||
return @r
|
|
@ -0,0 +1,19 @@
|
|||
var @this as this
|
||||
|
||||
$start
|
||||
@cond := invokeStatic `Foo.bar()I`
|
||||
if @cond == 0 then goto $zero else goto $nonzero
|
||||
$zero
|
||||
@a := new A
|
||||
@tmp1 := null
|
||||
field A.foo @a := @tmp1 as `Ljava/lang/Object;`
|
||||
goto $joint
|
||||
$nonzero
|
||||
@b := new B
|
||||
@tmp2 := 23
|
||||
field B.bar @b := @tmp2 as I
|
||||
field B.boo @b := @tmp2 as I
|
||||
goto $joint
|
||||
$joint
|
||||
@c := phi @a from $zero, @b from $nonzero
|
||||
return @c
|
|
@ -0,0 +1,19 @@
|
|||
var @this as this
|
||||
|
||||
$start
|
||||
@cond := invokeStatic `Foo.bar()I`
|
||||
if @cond == 0 then goto $zero else goto $nonzero
|
||||
$zero
|
||||
@a := new A
|
||||
@tmp1 := null
|
||||
field A.foo @a := @tmp1 as `Ljava/lang/Object;`
|
||||
goto $joint
|
||||
$nonzero
|
||||
@b := new B
|
||||
@tmp2 := 23
|
||||
field B.bar @b := @tmp2 as I
|
||||
field B.boo @b := @tmp2 as I
|
||||
goto $joint
|
||||
$joint
|
||||
@c := phi @a from $zero, @b from $nonzero
|
||||
return @c
|
|
@ -0,0 +1,23 @@
|
|||
var @this as this
|
||||
|
||||
$start
|
||||
@cond := invokeStatic `Foo.bar()I`
|
||||
if @cond == 0 then goto $zero else goto $nonzero
|
||||
$zero
|
||||
@a := new A
|
||||
@tmp1 := null
|
||||
field A.foo @a := @tmp1 as `Ljava/lang/Object;`
|
||||
goto $joint
|
||||
$nonzero
|
||||
@b := new B
|
||||
@tmp2 := 23
|
||||
field B.bar @b := @tmp2 as I
|
||||
field B.boo @b := @tmp2 as I
|
||||
field B.s := @b as `LB;`
|
||||
goto $joint
|
||||
$joint
|
||||
@c := phi @a from $zero, @b from $nonzero
|
||||
@tmp3 := 12.0F
|
||||
field C.baz @c := @tmp3 as F
|
||||
@r := field B.bar @c as I
|
||||
return @r
|
|
@ -0,0 +1,23 @@
|
|||
var @this as this
|
||||
|
||||
$start
|
||||
@cond := invokeStatic `Foo.bar()I`
|
||||
if @cond == 0 then goto $zero else goto $nonzero
|
||||
$zero
|
||||
@a := new A
|
||||
@tmp1 := null
|
||||
field A.foo @a := @tmp1 as `Ljava/lang/Object;`
|
||||
goto $joint
|
||||
$nonzero
|
||||
@b := new B
|
||||
@tmp2 := 23
|
||||
field B.bar @b := @tmp2 as I
|
||||
field B.boo @b := @tmp2 as I
|
||||
field B.s := @b as `LB;`
|
||||
goto $joint
|
||||
$joint
|
||||
@c := phi @a from $zero, @b from $nonzero
|
||||
@tmp3 := 12.0F
|
||||
field C.baz @c := @tmp3 as F
|
||||
@r := field B.bar @c as I
|
||||
return @r
|
|
@ -0,0 +1,24 @@
|
|||
var @this as this
|
||||
|
||||
$start
|
||||
@cond := invokeStatic `Foo.bar()I`
|
||||
if @cond == 0 then goto $zero else goto $nonzero
|
||||
$zero
|
||||
@a := new A
|
||||
@tmp1 := null
|
||||
field A.foo @a := @tmp1 as `Ljava/lang/Object;`
|
||||
goto $joint
|
||||
$nonzero
|
||||
@b := new B
|
||||
@tmp2 := 23
|
||||
field B.bar @b := @tmp2 as I
|
||||
field B.boo @b := @tmp2 as I
|
||||
@x := new B
|
||||
goto $joint
|
||||
$joint
|
||||
@c := phi @a from $zero, @b from $nonzero
|
||||
@d := phi @a from $zero, @x from $nonzero
|
||||
@tmp3 := 12.0F
|
||||
field C.baz @c := @tmp3 as F
|
||||
@r := field B.bar @c as I
|
||||
return @r
|
|
@ -0,0 +1,24 @@
|
|||
var @this as this
|
||||
|
||||
$start
|
||||
@cond := invokeStatic `Foo.bar()I`
|
||||
if @cond == 0 then goto $zero else goto $nonzero
|
||||
$zero
|
||||
@a := new A
|
||||
@tmp1 := null
|
||||
field A.foo @a := @tmp1 as `Ljava/lang/Object;`
|
||||
goto $joint
|
||||
$nonzero
|
||||
@b := new B
|
||||
@tmp2 := 23
|
||||
field B.bar @b := @tmp2 as I
|
||||
field B.boo @b := @tmp2 as I
|
||||
@x := new B
|
||||
goto $joint
|
||||
$joint
|
||||
@c := phi @a from $zero, @b from $nonzero
|
||||
@d := phi @a from $zero, @x from $nonzero
|
||||
@tmp3 := 12.0F
|
||||
field C.baz @c := @tmp3 as F
|
||||
@r := field B.bar @c as I
|
||||
return @r
|
|
@ -0,0 +1,27 @@
|
|||
var @this as this
|
||||
|
||||
$start
|
||||
@cond := invokeStatic `Foo.bar()I`
|
||||
if @cond == 0 then goto $zero else goto $nonzero
|
||||
$zero
|
||||
@a$foo := null
|
||||
@a$baz := 0.0F
|
||||
@a$bar := 0
|
||||
@tmp1 := null
|
||||
@a$foo_1 := @tmp1
|
||||
goto $joint
|
||||
$nonzero
|
||||
@b$bar := 0
|
||||
@b$boo := 0
|
||||
@b$baz := 0.0F
|
||||
@tmp2 := 23
|
||||
@b$bar_1 := @tmp2
|
||||
@b$boo_1 := @tmp2
|
||||
goto $joint
|
||||
$joint
|
||||
@c$baz := phi @a$baz from $zero, @b$baz from $nonzero
|
||||
@c$bar := phi @a$bar from $zero, @b$bar_1 from $nonzero
|
||||
@tmp3 := 12.0F
|
||||
@c$baz_1 := @tmp3
|
||||
@r := @c$bar
|
||||
return @r
|
|
@ -0,0 +1,22 @@
|
|||
var @this as this
|
||||
|
||||
$start
|
||||
@cond := invokeStatic `Foo.bar()I`
|
||||
if @cond == 0 then goto $zero else goto $nonzero
|
||||
$zero
|
||||
@a := new A
|
||||
@tmp1 := null
|
||||
field A.foo @a := @tmp1 as `Ljava/lang/Object;`
|
||||
goto $joint
|
||||
$nonzero
|
||||
@b := new B
|
||||
@tmp2 := 23
|
||||
field B.bar @b := @tmp2 as I
|
||||
field B.boo @b := @tmp2 as I
|
||||
goto $joint
|
||||
$joint
|
||||
@c := phi @a from $zero, @b from $nonzero
|
||||
@tmp3 := 12.0F
|
||||
field C.baz @c := @tmp3 as F
|
||||
@r := field B.bar @c as I
|
||||
return @r
|
|
@ -0,0 +1,11 @@
|
|||
var @this as this
|
||||
|
||||
$start
|
||||
@x$foo := null
|
||||
@x$bar := 0
|
||||
@a := 'qwe'
|
||||
@x$foo_1 := @a
|
||||
@b := 123
|
||||
@x$bar_1 := @b
|
||||
@y := @x$bar_1
|
||||
return @y
|
|
@ -0,0 +1,10 @@
|
|||
var @this as this
|
||||
|
||||
$start
|
||||
@x := new X
|
||||
@a := 'qwe'
|
||||
field X.foo @x := @a as `Ljava/lang/String;`
|
||||
@b := 123
|
||||
field X.bar @x := @b as I
|
||||
@y := field X.bar @x as I
|
||||
return @y
|
|
@ -0,0 +1,15 @@
|
|||
var @this as this
|
||||
|
||||
$start
|
||||
@cond := invokeStatic `Foo.bar()I`
|
||||
if @cond == 0 then goto $zero else goto $nonzero
|
||||
$zero
|
||||
@a := 0
|
||||
goto $joint
|
||||
$nonzero
|
||||
@b := 1
|
||||
@b_1 := 2
|
||||
goto $joint
|
||||
$joint
|
||||
@c := phi @a from $zero, @b_1 from $nonzero
|
||||
return @c
|
|
@ -0,0 +1,15 @@
|
|||
var @this as this
|
||||
|
||||
$start
|
||||
@cond := invokeStatic `Foo.bar()I`
|
||||
if @cond == 0 then goto $zero else goto $nonzero
|
||||
$zero
|
||||
@a := 0
|
||||
goto $joint
|
||||
$nonzero
|
||||
@b := 1
|
||||
@b := 2
|
||||
goto $joint
|
||||
$joint
|
||||
@c := phi @a from $zero, @b from $nonzero
|
||||
return @c
|
Loading…
Reference in New Issue
Block a user