diff --git a/core/src/main/java/org/teavm/model/analysis/EscapeAnalysis.java b/core/src/main/java/org/teavm/model/analysis/EscapeAnalysis.java index 940396f26..8fa0bbc31 100644 --- a/core/src/main/java/org/teavm/model/analysis/EscapeAnalysis.java +++ b/core/src/main/java/org/teavm/model/analysis/EscapeAnalysis.java @@ -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 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> fields) { + class Task { + int index; + FieldReference field; + Task(int index, FieldReference field) { + this.index = index; + this.field = field; + } + } + Queue 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 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 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> fields) { List> 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> fields; + Map 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 diff --git a/core/src/main/java/org/teavm/model/optimization/ScalarReplacement.java b/core/src/main/java/org/teavm/model/optimization/ScalarReplacement.java index 13ca652e3..be87f579d 100644 --- a/core/src/main/java/org/teavm/model/optimization/ScalarReplacement.java +++ b/core/src/main/java/org/teavm/model/optimization/ScalarReplacement.java @@ -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 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> fieldMappings; - public ScalarReplacementVisitor(EscapeAnalysis escapeAnalysis, ClassReaderSource classSource, + public ScalarReplacementVisitor(EscapeAnalysis escapeAnalysis, List> 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); } diff --git a/core/src/main/java/org/teavm/model/text/ListingLexer.java b/core/src/main/java/org/teavm/model/text/ListingLexer.java index d8ffdc43d..b13ea6e11 100644 --- a/core/src/main/java/org/teavm/model/text/ListingLexer.java +++ b/core/src/main/java/org/teavm/model/text/ListingLexer.java @@ -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; } diff --git a/core/src/main/java/org/teavm/model/util/PhiUpdater.java b/core/src/main/java/org/teavm/model/util/PhiUpdater.java index 3a8d99323..57bbe40ad 100644 --- a/core/src/main/java/org/teavm/model/util/PhiUpdater.java +++ b/core/src/main/java/org/teavm/model/util/PhiUpdater.java @@ -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) { diff --git a/core/src/test/java/org/teavm/model/optimization/test/ScalarReplacementTest.java b/core/src/test/java/org/teavm/model/optimization/test/ScalarReplacementTest.java new file mode 100644 index 000000000..4118bffc2 --- /dev/null +++ b/core/src/test/java/org/teavm/model/optimization/test/ScalarReplacementTest.java @@ -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); + } +} diff --git a/core/src/test/java/org/teavm/model/util/test/PhiUpdaterTest.java b/core/src/test/java/org/teavm/model/util/test/PhiUpdaterTest.java index bf22ae506..86a232e77 100644 --- a/core/src/test/java/org/teavm/model/util/test/PhiUpdaterTest.java +++ b/core/src/test/java/org/teavm/model/util/test/PhiUpdaterTest.java @@ -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"; diff --git a/core/src/test/resources/model/optimization/scalar-replacement/copy.expected.txt b/core/src/test/resources/model/optimization/scalar-replacement/copy.expected.txt new file mode 100644 index 000000000..248f38246 --- /dev/null +++ b/core/src/test/resources/model/optimization/scalar-replacement/copy.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 \ No newline at end of file diff --git a/core/src/test/resources/model/optimization/scalar-replacement/copy.original.txt b/core/src/test/resources/model/optimization/scalar-replacement/copy.original.txt new file mode 100644 index 000000000..7ba0b7589 --- /dev/null +++ b/core/src/test/resources/model/optimization/scalar-replacement/copy.original.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/optimization/scalar-replacement/escapingPhi.expected.txt b/core/src/test/resources/model/optimization/scalar-replacement/escapingPhi.expected.txt new file mode 100644 index 000000000..e9153cd98 --- /dev/null +++ b/core/src/test/resources/model/optimization/scalar-replacement/escapingPhi.expected.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/optimization/scalar-replacement/escapingPhi.original.txt b/core/src/test/resources/model/optimization/scalar-replacement/escapingPhi.original.txt new file mode 100644 index 000000000..e9153cd98 --- /dev/null +++ b/core/src/test/resources/model/optimization/scalar-replacement/escapingPhi.original.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/optimization/scalar-replacement/escapingPhiReceiver.expected.txt b/core/src/test/resources/model/optimization/scalar-replacement/escapingPhiReceiver.expected.txt new file mode 100644 index 000000000..397b80b2c --- /dev/null +++ b/core/src/test/resources/model/optimization/scalar-replacement/escapingPhiReceiver.expected.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/optimization/scalar-replacement/escapingPhiReceiver.original.txt b/core/src/test/resources/model/optimization/scalar-replacement/escapingPhiReceiver.original.txt new file mode 100644 index 000000000..397b80b2c --- /dev/null +++ b/core/src/test/resources/model/optimization/scalar-replacement/escapingPhiReceiver.original.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/optimization/scalar-replacement/escapingPhiSource.expected.txt b/core/src/test/resources/model/optimization/scalar-replacement/escapingPhiSource.expected.txt new file mode 100644 index 000000000..7ec343011 --- /dev/null +++ b/core/src/test/resources/model/optimization/scalar-replacement/escapingPhiSource.expected.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/optimization/scalar-replacement/escapingPhiSource.original.txt b/core/src/test/resources/model/optimization/scalar-replacement/escapingPhiSource.original.txt new file mode 100644 index 000000000..7ec343011 --- /dev/null +++ b/core/src/test/resources/model/optimization/scalar-replacement/escapingPhiSource.original.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/optimization/scalar-replacement/escapingSharedPhiSource.expected.txt b/core/src/test/resources/model/optimization/scalar-replacement/escapingSharedPhiSource.expected.txt new file mode 100644 index 000000000..8b61f2732 --- /dev/null +++ b/core/src/test/resources/model/optimization/scalar-replacement/escapingSharedPhiSource.expected.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/optimization/scalar-replacement/escapingSharedPhiSource.original.txt b/core/src/test/resources/model/optimization/scalar-replacement/escapingSharedPhiSource.original.txt new file mode 100644 index 000000000..8b61f2732 --- /dev/null +++ b/core/src/test/resources/model/optimization/scalar-replacement/escapingSharedPhiSource.original.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/optimization/scalar-replacement/phi.expected.txt b/core/src/test/resources/model/optimization/scalar-replacement/phi.expected.txt new file mode 100644 index 000000000..c654036ac --- /dev/null +++ b/core/src/test/resources/model/optimization/scalar-replacement/phi.expected.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/optimization/scalar-replacement/phi.original.txt b/core/src/test/resources/model/optimization/scalar-replacement/phi.original.txt new file mode 100644 index 000000000..383b10499 --- /dev/null +++ b/core/src/test/resources/model/optimization/scalar-replacement/phi.original.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/optimization/scalar-replacement/simple.expected.txt b/core/src/test/resources/model/optimization/scalar-replacement/simple.expected.txt new file mode 100644 index 000000000..e8fdce722 --- /dev/null +++ b/core/src/test/resources/model/optimization/scalar-replacement/simple.expected.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/optimization/scalar-replacement/simple.original.txt b/core/src/test/resources/model/optimization/scalar-replacement/simple.original.txt new file mode 100644 index 000000000..17f90adb9 --- /dev/null +++ b/core/src/test/resources/model/optimization/scalar-replacement/simple.original.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/util/phi-updater/phiIncoming.expected.txt b/core/src/test/resources/model/util/phi-updater/phiIncoming.expected.txt new file mode 100644 index 000000000..813bcdf4b --- /dev/null +++ b/core/src/test/resources/model/util/phi-updater/phiIncoming.expected.txt @@ -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 \ No newline at end of file diff --git a/core/src/test/resources/model/util/phi-updater/phiIncoming.original.txt b/core/src/test/resources/model/util/phi-updater/phiIncoming.original.txt new file mode 100644 index 000000000..8d77ca62d --- /dev/null +++ b/core/src/test/resources/model/util/phi-updater/phiIncoming.original.txt @@ -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 \ No newline at end of file