From 4ead605cf602f553e2de3ef928496eed58746788 Mon Sep 17 00:00:00 2001 From: dibyendumajumdar Date: Sun, 26 Jan 2025 15:37:18 +0000 Subject: [PATCH] SCCP: some more test cases Also introduce compiler options to control steps / debug info --- ...ChaitinGraphColoringRegisterAllocator.java | 12 +- .../ezlang/compiler/CompiledFunction.java | 5 + .../ezlang/compiler/Compiler.java | 16 +- .../ezlang/compiler/EnterSSA.java | 7 +- .../ezlang/compiler/ExitSSA.java | 9 +- .../ezlang/compiler/Optimizer.java | 16 +- .../ezlang/compiler/Options.java | 24 ++ .../SparseConditionalConstantPropagation.java | 7 +- .../compiler/TestChaitinRegAllocator.java | 2 +- .../ezlang/compiler/TestSCCP.java | 6 +- .../ezlang/compiler/TestSSATransform.java | 9 +- .../ezlang/interpreter/TestInterpreter.java | 269 +++++++++++++++++- 12 files changed, 350 insertions(+), 32 deletions(-) create mode 100644 optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Options.java diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/ChaitinGraphColoringRegisterAllocator.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/ChaitinGraphColoringRegisterAllocator.java index 47a03b9..abdce9f 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/ChaitinGraphColoringRegisterAllocator.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/ChaitinGraphColoringRegisterAllocator.java @@ -17,10 +17,10 @@ */ public class ChaitinGraphColoringRegisterAllocator { - public Map assignRegisters(CompiledFunction function, int numRegisters) { + public Map assignRegisters(CompiledFunction function, int numRegisters, EnumSet options) { if (function.isSSA) throw new IllegalStateException("Register allocation should be done after exiting SSA"); // Remove useless copy operations - InterferenceGraph g = coalesce(function); + InterferenceGraph g = coalesce(function, options); // Get used registers Set registers = registersInIR(function); // Create color set @@ -36,6 +36,8 @@ public Map assignRegisters(CompiledFunction function, int numR updateInstructions(function, assignments); // Compute and set the new framesize function.setFrameSize(computeFrameSize(assignments)); + if (options.contains(Options.DUMP_POST_CHAITIN_IR)) + function.dumpIR(false, "Post Chaitin Register Allocation"); return assignments; } @@ -83,13 +85,17 @@ private void updateInstructions(CompiledFunction function, Map /** * Chaitin: coalesce_nodes - coalesce away copy operations */ - public InterferenceGraph coalesce(CompiledFunction function) { + public InterferenceGraph coalesce(CompiledFunction function, EnumSet options) { boolean changed = true; InterferenceGraph igraph = null; while (changed) { igraph = new InterferenceGraphBuilder().build(function); changed = coalesceCopyOperations(function, igraph); } + if (options.contains(Options.DUMP_CHAITIN_COALESCE)) { + System.out.println("Post Chaitin Coalesce Registers"); + System.out.println(function.toStr(new StringBuilder(), false)); + } return igraph; } diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java index 8cd4c23..a686e8e 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java @@ -566,6 +566,11 @@ public StringBuilder toStr(StringBuilder sb, boolean verbose) { return sb; } + public void dumpIR(boolean verbose, String title) { + System.out.println(title); + System.out.println(toStr(new StringBuilder(), verbose)); + } + public void livenessAnalysis() { new Liveness(this); this.hasLiveness = true; diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java index e390fd1..df64e5c 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java @@ -8,24 +8,26 @@ import com.compilerprogramming.ezlang.types.Type; import com.compilerprogramming.ezlang.types.TypeDictionary; +import java.util.EnumSet; + public class Compiler { - private void compile(TypeDictionary typeDictionary, boolean opt) { + private void compile(TypeDictionary typeDictionary, EnumSet options) { for (Symbol symbol: typeDictionary.getLocalSymbols()) { if (symbol instanceof Symbol.FunctionTypeSymbol functionSymbol) { Type.TypeFunction functionType = (Type.TypeFunction) functionSymbol.type; var function = new CompiledFunction(functionSymbol); + if (options.contains(Options.DUMP_INITIAL_IR)) + function.dumpIR(false, "Initial IR"); functionType.code = function; - if (opt) { - new Optimizer().optimize(function); - } + new Optimizer().optimize(function, options); } } } public TypeDictionary compileSrc(String src) { - return compileSrc(src, false); + return compileSrc(src, EnumSet.noneOf(Options.class)); } - public TypeDictionary compileSrc(String src, boolean opt) { + public TypeDictionary compileSrc(String src, EnumSet options) { Parser parser = new Parser(); var program = parser.parse(new Lexer(src)); var typeDict = new TypeDictionary(); @@ -33,7 +35,7 @@ public TypeDictionary compileSrc(String src, boolean opt) { sema.analyze(program); var sema2 = new SemaAssignTypes(typeDict); sema2.analyze(program); - compile(typeDict, opt); + compile(typeDict, options); return typeDict; } public static String dumpIR(TypeDictionary typeDictionary) { diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/EnterSSA.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/EnterSSA.java index 9365c82..13a8556 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/EnterSSA.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/EnterSSA.java @@ -33,16 +33,21 @@ public class EnterSSA { int[] counters; VersionStack[] stacks; - public EnterSSA(CompiledFunction bytecodeFunction) { + public EnterSSA(CompiledFunction bytecodeFunction, EnumSet options) { this.function = bytecodeFunction; setupGlobals(); computeDomTreeAndDominanceFrontiers(); + if (options.contains(Options.DUMP_PRE_SSA_DOMTREE)) { + System.out.println("Pre SSA Dominator Tree"); + System.out.println(domTree.generateDotOutput()); + } this.blocks = domTree.blocks; // the blocks are ordered reverse post order findNonLocalNames(); insertPhis(); renameVars(); bytecodeFunction.isSSA = true; bytecodeFunction.hasLiveness = false; + if (options.contains(Options.DUMP_SSA_IR)) bytecodeFunction.dumpIR(false, "Post SSA IR"); } private void computeDomTreeAndDominanceFrontiers() { diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/ExitSSA.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/ExitSSA.java index 7cec37a..745e181 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/ExitSSA.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/ExitSSA.java @@ -17,16 +17,21 @@ public class ExitSSA { NameStack[] stacks; DominatorTree tree; - public ExitSSA(CompiledFunction function) { + public ExitSSA(CompiledFunction function, EnumSet options) { this.function = function; if (!function.isSSA) throw new IllegalStateException(); function.livenessAnalysis(); - System.out.println(function.toStr(new StringBuilder(), true)); + if (options.contains(Options.DUMP_SSA_LIVENESS)) function.dumpIR(true, "SSA Liveness Analysis"); tree = new DominatorTree(function.entry); + if (options.contains(Options.DUMP_SSA_DOMTREE)) { + System.out.println("Pre SSA Dominator Tree"); + System.out.println(tree.generateDotOutput()); + } initStack(); insertCopies(function.entry); removePhis(); function.isSSA = false; + if (options.contains(Options.DUMP_POST_SSA_IR)) function.dumpIR(false, "After exiting SSA"); } private void removePhis() { diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Optimizer.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Optimizer.java index 8eeebbc..54a63a8 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Optimizer.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Optimizer.java @@ -1,11 +1,17 @@ package com.compilerprogramming.ezlang.compiler; +import java.util.EnumSet; + public class Optimizer { - public void optimize(CompiledFunction function) { - new EnterSSA(function); - new SparseConditionalConstantPropagation().constantPropagation(function).apply(); - new ExitSSA(function); - new ChaitinGraphColoringRegisterAllocator().assignRegisters(function, 64); + public void optimize(CompiledFunction function, EnumSet options) { + if (options.contains(Options.OPTIMIZE)) { + new EnterSSA(function, options); + if (options.contains(Options.SCCP)) + new SparseConditionalConstantPropagation().constantPropagation(function).apply(options); + new ExitSSA(function, options); + } + if (options.contains(Options.REGALLOC)) + new ChaitinGraphColoringRegisterAllocator().assignRegisters(function, 64, options); } } diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Options.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Options.java new file mode 100644 index 0000000..06a0c42 --- /dev/null +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Options.java @@ -0,0 +1,24 @@ +package com.compilerprogramming.ezlang.compiler; + +import java.util.EnumSet; + +public enum Options { + OPTIMIZE, + SCCP, + REGALLOC, + DUMP_INITIAL_IR, + DUMP_PRE_SSA_DOMTREE, + DUMP_SSA_IR, + DUMP_SCCP_PREAPPLY, + DUMP_SCCP_POSTAPPLY, + DUMP_SSA_LIVENESS, + DUMP_SSA_DOMTREE, + DUMP_POST_SSA_IR, + DUMP_INTERFERENCE_GRAPH, + DUMP_CHAITIN_COALESCE, + DUMP_POST_CHAITIN_IR; + + public static final EnumSet NONE = EnumSet.noneOf(Options.class); + public static final EnumSet OPT = EnumSet.of(Options.OPTIMIZE,Options.SCCP,Options.REGALLOC); + public static final EnumSet OPT_VERBOSE = EnumSet.allOf(Options.class); +} diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SparseConditionalConstantPropagation.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SparseConditionalConstantPropagation.java index a8e77e3..92f5fd6 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SparseConditionalConstantPropagation.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SparseConditionalConstantPropagation.java @@ -120,7 +120,7 @@ private void init(CompiledFunction function) { visited = new BitSet(); } - public SparseConditionalConstantPropagation apply() { + public SparseConditionalConstantPropagation apply(EnumSet options) { /* The constant propagation algorithm does not change the flow graph - it computes information about the flow graph. The compiler now uses this information to improve @@ -137,10 +137,15 @@ public SparseConditionalConstantPropagation apply() { Bob Morgan. Building an Optimizing Compiler */ + if (options.contains(Options.DUMP_SCCP_PREAPPLY)) { + System.out.println("SCCP analysis\n"); + System.out.println(toString()); + } markExecutableBlocks(); removeBranchesThatAreNotExecutable(); replaceVarsWithConstants(); // Unreachable blocks are eliminated as there are no paths to them + if (options.contains(Options.DUMP_SCCP_POSTAPPLY)) function.dumpIR(false, "Post SCCP\n"); return this; } diff --git a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestChaitinRegAllocator.java b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestChaitinRegAllocator.java index 4197e1f..e279cef 100644 --- a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestChaitinRegAllocator.java +++ b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestChaitinRegAllocator.java @@ -15,7 +15,7 @@ public void test4() { Assert.assertEquals(2, edges.size()); Assert.assertTrue(edges.contains(new InterferenceGraph.Edge(0, 1))); Assert.assertTrue(edges.contains(new InterferenceGraph.Edge(0, 2))); - var regAssignments = new ChaitinGraphColoringRegisterAllocator().assignRegisters(function, 64); + var regAssignments = new ChaitinGraphColoringRegisterAllocator().assignRegisters(function, 64, Options.OPT); String result = function.toStr(new StringBuilder(), false).toString(); Assert.assertEquals(""" L0: diff --git a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSCCP.java b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSCCP.java index 530fbd9..bd25216 100644 --- a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSCCP.java +++ b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSCCP.java @@ -5,6 +5,7 @@ import org.junit.Test; import java.util.BitSet; +import java.util.EnumSet; public class TestSCCP { @@ -12,15 +13,16 @@ String compileSrc(String src) { var compiler = new Compiler(); var typeDict = compiler.compileSrc(src); StringBuilder sb = new StringBuilder(); + var options = Options.NONE; for (Symbol s : typeDict.bindings.values()) { if (s instanceof Symbol.FunctionTypeSymbol f) { var functionBuilder = (CompiledFunction) f.code(); - new EnterSSA(functionBuilder); + new EnterSSA(functionBuilder, options); BasicBlock.toStr(sb, functionBuilder.entry, new BitSet(), false); //functionBuilder.toDot(sb, false); var sccp = new SparseConditionalConstantPropagation().constantPropagation(functionBuilder); sb.append(sccp.toString()); - sccp.apply(); + sccp.apply(options); sb.append("After SCCP changes:\n"); functionBuilder.toStr(sb, false); } diff --git a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSSATransform.java b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSSATransform.java index 17ff310..27387b2 100644 --- a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSSATransform.java +++ b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSSATransform.java @@ -9,6 +9,7 @@ import java.util.Arrays; import java.util.BitSet; +import java.util.EnumSet; public class TestSSATransform { @@ -23,11 +24,11 @@ String compileSrc(String src) { sb.append("Before SSA\n"); sb.append("==========\n"); BasicBlock.toStr(sb, functionBuilder.entry, new BitSet(), false); - new EnterSSA(functionBuilder); + new EnterSSA(functionBuilder, Options.NONE); sb.append("After SSA\n"); sb.append("=========\n"); BasicBlock.toStr(sb, functionBuilder.entry, new BitSet(), false); - new ExitSSA(functionBuilder); + new ExitSSA(functionBuilder, Options.NONE); sb.append("After exiting SSA\n"); sb.append("=================\n"); BasicBlock.toStr(sb, functionBuilder.entry, new BitSet(), false); @@ -680,7 +681,7 @@ public void testLostCopyProblem() { ret x2 """; Assert.assertEquals(expected, function.toStr(new StringBuilder(), false).toString()); - new ExitSSA(function); + new ExitSSA(function, EnumSet.noneOf(Options.class)); expected = """ L0: arg p @@ -748,7 +749,7 @@ public void testSwapProblem() { L1: """; Assert.assertEquals(expected, function.toStr(new StringBuilder(), false).toString()); - new ExitSSA(function); + new ExitSSA(function, EnumSet.noneOf(Options.class)); expected = """ L0: arg p diff --git a/optvm/src/test/java/com/compilerprogramming/ezlang/interpreter/TestInterpreter.java b/optvm/src/test/java/com/compilerprogramming/ezlang/interpreter/TestInterpreter.java index 5d49505..2ccaca5 100644 --- a/optvm/src/test/java/com/compilerprogramming/ezlang/interpreter/TestInterpreter.java +++ b/optvm/src/test/java/com/compilerprogramming/ezlang/interpreter/TestInterpreter.java @@ -1,17 +1,20 @@ package com.compilerprogramming.ezlang.interpreter; import com.compilerprogramming.ezlang.compiler.Compiler; +import com.compilerprogramming.ezlang.compiler.Options; import org.junit.Assert; import org.junit.Test; +import java.util.EnumSet; + public class TestInterpreter { Value compileAndRun(String src, String mainFunction) { - return compileAndRun(src, mainFunction, false); + return compileAndRun(src, mainFunction, Options.NONE); } - Value compileAndRun(String src, String mainFunction, boolean opt) { + Value compileAndRun(String src, String mainFunction, EnumSet options) { var compiler = new Compiler(); - var typeDict = compiler.compileSrc(src, opt); + var typeDict = compiler.compileSrc(src, options); var compiled = compiler.dumpIR(typeDict); System.out.println(compiled); var interpreter = new Interpreter(typeDict); @@ -140,7 +143,7 @@ func foo()->Int { return factorial(5); } """; - var value = compileAndRun(src, "foo", true); + var value = compileAndRun(src, "foo", Options.OPT); Assert.assertNotNull(value); Assert.assertTrue(value instanceof Value.IntegerValue integerValue && integerValue.value == 120); @@ -168,7 +171,7 @@ func foo() { return fib(10); } """; - var value = compileAndRun(src, "foo", true); + var value = compileAndRun(src, "foo", Options.OPT); Assert.assertNotNull(value); Assert.assertTrue(value instanceof Value.IntegerValue integerValue && integerValue.value == 89); @@ -183,9 +186,263 @@ func foo()->Int { return 3; } """; - var value = compileAndRun(src, "foo", true); + var value = compileAndRun(src, "foo", Options.OPT); Assert.assertNotNull(value); Assert.assertTrue(value instanceof Value.IntegerValue integerValue && integerValue.value == 2); } + + // 4.1.2 optimizer evaluation + // propagating through expressions + @Test + public void testFunction11() { + String src = """ + func bar(data: [Int]) { + var j = 1 + var k = 2 + var m = 4 + var n = k * m + j = n + j + data[0] = j + } + func foo()->Int { + var data = new [Int] {0} + bar(data) + return data[0] + } + """; + var value = compileAndRun(src, "foo", Options.OPT); + Assert.assertNotNull(value); + Assert.assertTrue(value instanceof Value.IntegerValue integerValue + && integerValue.value == 9); + } + + // 4.2.1 optimizer evaluation + // extended basic blocks + @Test + public void testFunction12() { + String src = """ + func bar(data: [Int]) { + var j = 12345 + if (data[0]) + data[1] = 1 + j - 1234 + else + data[2] = 123 + j + 10 + } + func foo() { + var data = new [Int] {0,0,0} + bar(data) + return data[0]+data[1]+data[2]; + } + """; + var value = compileAndRun(src, "foo", Options.OPT); + Assert.assertNotNull(value); + Assert.assertTrue(value instanceof Value.IntegerValue integerValue + && integerValue.value == 12478); + } + + // 4.2.1 optimizer evaluation + // extended basic blocks + @Test + public void testFunction13() { + String src = """ + func bar(data: [Int]) { + var j = 12345 + if (data[0]) + data[1] = 1 + j - 1234 + else + data[2] = 123 - j + 10 + } + func foo() { + var data = new [Int] {0,0,0} + bar(data) + return data[0]+data[1]+data[2]; + } + """; + var value = compileAndRun(src, "foo", Options.OPT); + Assert.assertNotNull(value); + Assert.assertTrue(value instanceof Value.IntegerValue integerValue + && integerValue.value == -12212); + } + + // 4.2.2 dominators + @Test + public void testFunction14() { + String src = """ + func bar(data: [Int]) { + var j = 5 + if (data[0]) + data[1] = 10 + else + data[2] = 15 + data[3] = j + 21 + } + func foo() { + var data = new [Int] {0,0,0,0} + bar(data) + return data[0]+data[1]+data[2]+data[3]; + } + """; + var value = compileAndRun(src, "foo", Options.OPT); + Assert.assertNotNull(value); + Assert.assertTrue(value instanceof Value.IntegerValue integerValue + && integerValue.value == 5+21+15); + } + + // 4.2.2 dominators + @Test + public void testFunction15() { + String src = """ + func bar(data: [Int]) { + var j = 5 + if (data[0]) + data[1] = j * 10 + else + data[2] = j * 15 + data[3] = j * 21 + } + func foo() { + var data = new [Int] {0,0,0,0} + bar(data) + return data[0]+data[1]+data[2]+data[3]; + } + """; + var value = compileAndRun(src, "foo", Options.OPT); + Assert.assertNotNull(value); + Assert.assertTrue(value instanceof Value.IntegerValue integerValue + && integerValue.value == 5*15+5*21); + } + + // 4.2.3 DAGs + @Test + public void testFunction16() { + String src = """ + func bar(data: [Int]) { + var j: Int + if (data[0]) { + j = 5 + data[1] = 10 + } + else { + data[2] = 15 + j = 5 + } + data[3] = j + 21 + } + func foo() { + var data = new [Int] {1,0,0,0} + bar(data) + return data[0]+data[1]+data[2]+data[3] + } + """; + var value = compileAndRun(src, "foo", Options.OPT); + Assert.assertNotNull(value); + Assert.assertTrue(value instanceof Value.IntegerValue integerValue + && integerValue.value == 1+10+5+21); + } + + // 4.2.3 DAGs + // Doesn't give the outcome + @Test + public void testFunction17() { + String src = """ + func bar(data: [Int]) { + var j: Int + var k: Int + if (data[0]) { + j = 4 + k = 6 + data[1] = j + } + else { + j = 7 + k = 3 + data[2] = k + } + data[3] = (j+k) * 21 + } + func foo() { + var data = new [Int] {1,0,0,0} + bar(data) + return data[0]+data[1]+data[2]+data[3] + } + """; + var value = compileAndRun(src, "foo", Options.OPT); + Assert.assertNotNull(value); + Assert.assertTrue(value instanceof Value.IntegerValue integerValue + && integerValue.value == 1+4+210); + } + + // 4.2.4 Loops + @Test + public void testFunction18() { + String src = """ + func bar(data: [Int]) { + var i: Int + var stop = data[0] + var j = 21 + i = 1 + while ( i < stop ) { + j = (j - 20) * 21; + i = i + 1 + } + data[1] = j + data[2] = i + } + func foo() { + var data = new [Int] {2,0,0} + bar(data) + return data[0]+data[1]+data[2]; + } + """; + var value = compileAndRun(src, "foo", Options.OPT); + Assert.assertNotNull(value); + Assert.assertTrue(value instanceof Value.IntegerValue integerValue + && integerValue.value == 2+21+2); + } + + // 4.3 Conditional constants + @Test + public void testFunction19() { + String src = """ + func bar(data: [Int]) { + var j = 1 + if (j) j = 10 + else j = data[0] + data[0] = j * 21 + data[1] + } + func foo() { + var data = new [Int] {2,3} + bar(data) + return data[0]+data[1]; + } + """; + var value = compileAndRun(src, "foo", Options.OPT); + Assert.assertNotNull(value); + Assert.assertTrue(value instanceof Value.IntegerValue integerValue + && integerValue.value == 213+3); + } + + // 4.4 Conditional based assertions + @Test + public void testFunction20() { + String src = """ + func bar(data: [Int]) { + var j = data[0] + if (j == 5) + j = j * 21 + 25 / j + data[1] = j + } + func foo() { + var data = new [Int] {5,3} + bar(data) + return data[0]+data[1]; + } + """; + var value = compileAndRun(src, "foo", Options.OPT); + Assert.assertNotNull(value); + Assert.assertTrue(value instanceof Value.IntegerValue integerValue + && integerValue.value == 5+(5*21+25/5)); + } + }