/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.truffle.test.nodes.explosion;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.debug.BlackholeNode;
import org.graalvm.compiler.truffle.test.nodes.AbstractTestNode;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.nodes.ExplodeLoop.LoopExplosionKind;
import jdk.vm.ci.meta.JavaConstant;
public class UnrollingTestNode {
public static volatile int SideEffect;
public static volatile int SideEffect1;
public static volatile int SideEffect2;
public static volatile int SideEffect3;
private final int count;
public UnrollingTestNode(int count) {
this.count = count;
}
public static final String OUTSIDE_LOOP_MARKER = "OUTSIDE_LOOP_MARKER";
public static final String INSIDE_LOOP_MARKER = "INSIDE_LOOP_MARKER";
public static final String INSIDE_LOOP_MARKER_2 = "INSIDE_LOOP_MARKER_2";
public static final String OUTER_LOOP_INSIDE_LOOP_MARKER = "OUTER_LOOP_INSIDE_LOOP_MARKER";
public static final String CONTINUE_LOOP_MARKER = "CONTINUE_LOOP_MARKER";
public static final String AFTER_LOOP_MARKER = "AFTER_LOOP_MARKER";
public static int countBlackholeNodes(StructuredGraph graph, String val) {
int count = 0;
for (BlackholeNode bh : graph.getNodes().filter(BlackholeNode.class)) {
ValueNode v = bh.getValue();
if (v.isConstant()) {
JavaConstant jc = v.asJavaConstant();
if (jc.toValueString().replaceAll("\"", "").equals(val)) {
count++;
}
}
}
return count;
}
public class UnrollOnlyExample extends AbstractTestNode {
@ExplodeLoop(kind = LoopExplosionKind.FULL_UNROLL)
@Override
public int execute(VirtualFrame frame) {
for (int i = 0; i < count; i++) {
GraalDirectives.blackhole(INSIDE_LOOP_MARKER);
}
GraalDirectives.blackhole(AFTER_LOOP_MARKER);
return count;
}
}
public class ExplodeAlongLoopEndExample extends AbstractTestNode {
@ExplodeLoop(kind = LoopExplosionKind.FULL_EXPLODE)
@Override
public int execute(VirtualFrame frame) {
for (int i = 0; i < count; i++) {
GraalDirectives.blackhole(INSIDE_LOOP_MARKER);
SideEffect = i;
if (i == SideEffect2) {
// exit the loop
GraalDirectives.blackhole(OUTSIDE_LOOP_MARKER);
GraalDirectives.blackhole(i);
continue;
}
}
GraalDirectives.blackhole(AFTER_LOOP_MARKER);
return count;
}
}
public class FullUnrollUntilReturnExample extends AbstractTestNode {
@ExplodeLoop(kind = LoopExplosionKind.FULL_UNROLL_UNTIL_RETURN)
@Override
public int execute(VirtualFrame frame) {
for (int i = 0; i < count; i++) {
GraalDirectives.blackhole(INSIDE_LOOP_MARKER);
SideEffect = i;
if (i == SideEffect2) {
// exit the loop
GraalDirectives.blackhole(OUTSIDE_LOOP_MARKER);
GraalDirectives.blackhole(i);
CompilerAsserts.partialEvaluationConstant(i);
return i;
}
// random code
// loop end -> unroll
}
GraalDirectives.blackhole(AFTER_LOOP_MARKER);
return count;
}
}
public class FullUnrollUntilReturnNoLoop extends AbstractTestNode {
@ExplodeLoop(kind = LoopExplosionKind.FULL_UNROLL_UNTIL_RETURN)
@Override
public int execute(VirtualFrame frame) {
return count;
}
}
public class FullUnrollUntilReturnConsecutiveLoops extends AbstractTestNode {
@ExplodeLoop(kind = LoopExplosionKind.FULL_UNROLL_UNTIL_RETURN)
@Override
public int execute(VirtualFrame frame) {
for (int i = 0; i < count; i++) {
GraalDirectives.blackhole(INSIDE_LOOP_MARKER);
SideEffect = i;
if (i == SideEffect2) {
// exit the loop
GraalDirectives.blackhole(OUTSIDE_LOOP_MARKER);
GraalDirectives.blackhole(i);
CompilerAsserts.partialEvaluationConstant(i);
return i;
}
// random code
// loop end -> unroll
}
for (int i = 0; i < count; i++) {
GraalDirectives.blackhole(INSIDE_LOOP_MARKER);
SideEffect = i;
if (i == SideEffect2) {
// exit the loop
GraalDirectives.blackhole(OUTSIDE_LOOP_MARKER);
GraalDirectives.blackhole(i);
CompilerAsserts.partialEvaluationConstant(i);
return i;
}
// random code
// loop end -> unroll
}
GraalDirectives.blackhole(AFTER_LOOP_MARKER);
return count;
}
}
public class FullUnrollUntilReturnNestedLoops extends AbstractTestNode {
@ExplodeLoop(kind = LoopExplosionKind.FULL_UNROLL_UNTIL_RETURN)
@Override
public int execute(VirtualFrame frame) {
for (int i = 0; i < count; i++) {
SideEffect = i;
for (int j = 0; j < count; j++) {
GraalDirectives.blackhole(INSIDE_LOOP_MARKER);
SideEffect = j;
if (i == SideEffect2) {
// exit the loop
GraalDirectives.blackhole(OUTSIDE_LOOP_MARKER);
GraalDirectives.blackhole(i);
CompilerAsserts.partialEvaluationConstant(i);
return j;
}
// random code
// loop end -> unroll
}
}
GraalDirectives.blackhole(AFTER_LOOP_MARKER);
return count;
}
}
public class FullUnrollUntilReturnNestedLoopsBreakInner extends AbstractTestNode {
@ExplodeLoop(kind = LoopExplosionKind.FULL_UNROLL_UNTIL_RETURN)
@Override
public int execute(VirtualFrame frame) {
for (int i = 0; i < count; i++) {
SideEffect = i;
for (int j = 0; j < count; j++) {
GraalDirectives.blackhole(INSIDE_LOOP_MARKER);
SideEffect = j;
if (i == SideEffect2) {
// exit the loop
GraalDirectives.blackhole(OUTSIDE_LOOP_MARKER);
GraalDirectives.blackhole(i);
CompilerAsserts.partialEvaluationConstant(i);
break;
}
// random code
// loop end -> unroll
}
}
GraalDirectives.blackhole(AFTER_LOOP_MARKER);
return count;
}
}
public class FullUnrollUntilReturnNestedLoopsContinueOuter01 extends AbstractTestNode {
@ExplodeLoop(kind = LoopExplosionKind.FULL_UNROLL_UNTIL_RETURN)
@Override
public int execute(VirtualFrame frame) {
/*
* Special case full unroll until return with a continue statement to the outer loop.
* UNTIL_RETURN implies the duplication of code paths along loop exits. Continue
* statements to outer loops create loop exits of the inner loop and continues of the
* outer loop.
*/
int i = 0;
while (true) {
if (i >= count) {
break;
}
CompilerAsserts.partialEvaluationConstant(i);
GraalDirectives.blackhole(OUTER_LOOP_INSIDE_LOOP_MARKER);
int j = 0;
inner: while (true) {
if (j >= count) {
break;
}
CompilerAsserts.partialEvaluationConstant(j);
GraalDirectives.blackhole(INSIDE_LOOP_MARKER);
if (SideEffect3 == j) {
CompilerAsserts.partialEvaluationConstant(j);
/* continue to outer loop */
break inner;
}
GraalDirectives.blackhole(INSIDE_LOOP_MARKER_2);
j++;
}
i++;
}
GraalDirectives.blackhole(AFTER_LOOP_MARKER);
return count;
}
}
public class FullUnrollUntilReturnNestedLoopsContinueOuter02 extends AbstractTestNode {
@ExplodeLoop(kind = LoopExplosionKind.FULL_UNROLL_UNTIL_RETURN)
@Override
public int execute(VirtualFrame frame) {
int i = 0;
outer: while (true) {
if (i >= count) {
break;
}
CompilerAsserts.partialEvaluationConstant(i);
GraalDirectives.blackhole(OUTER_LOOP_INSIDE_LOOP_MARKER);
int j = 0;
while (true) {
if (j >= count) {
break;
}
CompilerAsserts.partialEvaluationConstant(j);
GraalDirectives.blackhole(INSIDE_LOOP_MARKER);
if (SideEffect3 == j) {
i++;
GraalDirectives.blackhole(INSIDE_LOOP_MARKER);
SideEffect = i;
continue outer;
} else {
GraalDirectives.blackhole(INSIDE_LOOP_MARKER_2);
}
GraalDirectives.blackhole(INSIDE_LOOP_MARKER_2);
j++;
}
i++;
}
GraalDirectives.blackhole(AFTER_LOOP_MARKER);
return count;
}
}
public class FullUnrollUntilReturnNestedLoopsContinueOuter03 extends AbstractTestNode {
@ExplodeLoop(kind = LoopExplosionKind.FULL_UNROLL_UNTIL_RETURN)
@Override
public int execute(VirtualFrame frame) {
outer: for (int i = 0; i < count; i++) {
GraalDirectives.blackhole(OUTER_LOOP_INSIDE_LOOP_MARKER);
CompilerAsserts.partialEvaluationConstant(i);
for (int j = 0; j < count; j++) {
GraalDirectives.blackhole(INSIDE_LOOP_MARKER);
if (j == SideEffect3) {
GraalDirectives.blackhole(CONTINUE_LOOP_MARKER);
CompilerAsserts.partialEvaluationConstant(j);
continue outer;
}
}
}
GraalDirectives.blackhole(AFTER_LOOP_MARKER);
return count;
}
}
public class FullUnrollUntilReturnNestedLoopsContinueOuter04 extends AbstractTestNode {
@ExplodeLoop(kind = LoopExplosionKind.FULL_UNROLL_UNTIL_RETURN)
@Override
public int execute(VirtualFrame frame) {
outer: for (int i = 0; i < count; i++) {
GraalDirectives.blackhole(OUTER_LOOP_INSIDE_LOOP_MARKER);
CompilerAsserts.partialEvaluationConstant(i);
for (int j = 0; j < count; j++) {
GraalDirectives.blackhole(INSIDE_LOOP_MARKER);
if (j == SideEffect3) {
GraalDirectives.blackhole(CONTINUE_LOOP_MARKER);
CompilerAsserts.partialEvaluationConstant(j);
int x = i * j + 2 * i;
CompilerAsserts.partialEvaluationConstant(x);
SideEffect = x;
SideEffect1 = x;
continue outer;
}
}
}
GraalDirectives.blackhole(AFTER_LOOP_MARKER);
return count;
}
}
public class FullUnrollUntilReturnNestedLoopsContinueOuter05 extends AbstractTestNode {
@ExplodeLoop(kind = LoopExplosionKind.FULL_UNROLL_UNTIL_RETURN)
@Override
public int execute(VirtualFrame frame) {
for (int i = 0; i < count; i++) {
GraalDirectives.blackhole(INSIDE_LOOP_MARKER);
GraalDirectives.blackhole(OUTSIDE_LOOP_MARKER);
GraalDirectives.blackhole(i);
CompilerAsserts.partialEvaluationConstant(i);
}
outer: for (int i = 0; i < count; i++) {
GraalDirectives.blackhole(OUTER_LOOP_INSIDE_LOOP_MARKER);
CompilerAsserts.partialEvaluationConstant(i);
for (int j = 0; j < count; j++) {
GraalDirectives.blackhole(INSIDE_LOOP_MARKER);
if (j == SideEffect3) {
GraalDirectives.blackhole(CONTINUE_LOOP_MARKER);
CompilerAsserts.partialEvaluationConstant(j);
int x = i * j + 2 * i;
CompilerAsserts.partialEvaluationConstant(x);
SideEffect = x;
SideEffect1 = x;
continue outer;
}
if (j == SideEffect2) {
GraalDirectives.blackhole(CONTINUE_LOOP_MARKER);
CompilerAsserts.partialEvaluationConstant(j);
int x = i * j + 2 * i;
CompilerAsserts.partialEvaluationConstant(x);
SideEffect = x;
SideEffect1 = x;
break;
}
if (j == SideEffect1) {
GraalDirectives.blackhole(CONTINUE_LOOP_MARKER);
CompilerAsserts.partialEvaluationConstant(j);
int x = i * j + 2 * i;
CompilerAsserts.partialEvaluationConstant(x);
SideEffect = x;
SideEffect1 = x;
continue outer;
}
}
}
GraalDirectives.blackhole(AFTER_LOOP_MARKER);
return count;
}
}
public static class ExecutingUnrollUntilReturnTest {
public static volatile int ExecutedSideEffect1;
public static volatile int ExecutedSideEffect2;
public static volatile int ExecutedSideEffect3;
public static volatile int ExecutedSideEffect4;
public static volatile int ExecutedSideEffect5;
public static volatile int ExecutedSideEffect6;
public static volatile int SpecialSideEffect1;
public static volatile int SpecialSideEffect2;
public static volatile int SpecialSideEffect3;
public static volatile int SpecialSideEffect4;
public static volatile int SpecialSideEffect5;
public static volatile int SpecialSideEffect6;
public static volatile int SpecialSideEffect7;
public static volatile int SpecialSideEffect8;
public static volatile int SpecialSideEffect9;
public static volatile int SpecialSideEffect10;
public static volatile int SpecialSideEffect11;
public static volatile int SpecialSideEffect12;
public static int specialIterationNumber = 6;
@TruffleBoundary
public static int result() {
return ExecutedSideEffect1 + ExecutedSideEffect2 + ExecutedSideEffect3 + ExecutedSideEffect4 + ExecutedSideEffect5 + ExecutedSideEffect6 + SpecialSideEffect1 + SpecialSideEffect2 +
SpecialSideEffect3 + SpecialSideEffect4 + SpecialSideEffect5 + SpecialSideEffect6 + SpecialSideEffect7 + SpecialSideEffect8 + SpecialSideEffect9 + SpecialSideEffect10 +
SpecialSideEffect11 + SpecialSideEffect12;
}
public static void clearSpecialEffect() {
/*
* Special Unit test:
*
* In order to not only track how many times a certain loop exit marker is duplicated we
* also test the exact times a branch is executed at runtime. Therefore, we compare the
* number of times a field has been written in an interpreted execution of a method and
* a partial evaluated compiled execution of the method.
*
* We reset the test fields in between.
*/
ExecutedSideEffect1 = specialIterationNumber - 3;
ExecutedSideEffect2 = specialIterationNumber - 2;
ExecutedSideEffect3 = specialIterationNumber - 1;
ExecutedSideEffect4 = specialIterationNumber - 1;
ExecutedSideEffect5 = specialIterationNumber - 2;
ExecutedSideEffect6 = specialIterationNumber - 3;
SpecialSideEffect1 = 0;
SpecialSideEffect2 = 0;
SpecialSideEffect3 = 0;
SpecialSideEffect4 = 0;
SpecialSideEffect5 = 0;
SpecialSideEffect6 = 0;
SpecialSideEffect7 = 0;
SpecialSideEffect8 = 0;
SpecialSideEffect9 = 0;
SpecialSideEffect10 = 0;
SpecialSideEffect11 = 0;
SpecialSideEffect12 = 0;
}
public static int compiledInvocationCounts;
public static int interpretedInvocationCounts;
}
public class FullUnrollUntilReturnNestedLoopsContinueOuter06 extends AbstractTestNode {
@ExplodeLoop(kind = LoopExplosionKind.FULL_UNROLL_UNTIL_RETURN)
@Override
public int execute(VirtualFrame frame) {
l1: for (int i1 = 0; i1 < count; i1++) {
GraalDirectives.blackhole(OUTER_LOOP_INSIDE_LOOP_MARKER);
CompilerAsserts.partialEvaluationConstant(i1);
l2: for (int i2 = 0; i2 < count; i2++) {
GraalDirectives.blackhole(OUTER_LOOP_INSIDE_LOOP_MARKER);
CompilerAsserts.partialEvaluationConstant(2);
l3: for (int i3 = 0; i3 < count; i3++) {
GraalDirectives.blackhole(OUTER_LOOP_INSIDE_LOOP_MARKER);
CompilerAsserts.partialEvaluationConstant(3);
for (int i4 = 0; i4 < count; i4++) {
GraalDirectives.blackhole(OUTER_LOOP_INSIDE_LOOP_MARKER);
CompilerAsserts.partialEvaluationConstant(4);
if (i4 == ExecutingUnrollUntilReturnTest.ExecutedSideEffect1) {
GraalDirectives.blackhole(CONTINUE_LOOP_MARKER);
CompilerAsserts.partialEvaluationConstant(i4);
int x = i3 + i1 + 2 + i2 + i4;
CompilerAsserts.partialEvaluationConstant(x);
ExecutingUnrollUntilReturnTest.SpecialSideEffect1 += x;
ExecutingUnrollUntilReturnTest.SpecialSideEffect2 += x;
ExecutingUnrollUntilReturnTest.ExecutedSideEffect1 = 1024;
continue l1;
}
if (i4 == ExecutingUnrollUntilReturnTest.ExecutedSideEffect2) {
GraalDirectives.blackhole(CONTINUE_LOOP_MARKER);
CompilerAsserts.partialEvaluationConstant(i4);
int x = i3 + i1 + 2 + i2 + i4;
CompilerAsserts.partialEvaluationConstant(x);
ExecutingUnrollUntilReturnTest.SpecialSideEffect3 += x;
ExecutingUnrollUntilReturnTest.SpecialSideEffect4 += x;
ExecutingUnrollUntilReturnTest.ExecutedSideEffect2 = 1024;
continue l2;
}
if (i4 == ExecutingUnrollUntilReturnTest.ExecutedSideEffect3) {
GraalDirectives.blackhole(CONTINUE_LOOP_MARKER);
CompilerAsserts.partialEvaluationConstant(i4);
int x = i3 + i1 + 2 + i2 + i4;
CompilerAsserts.partialEvaluationConstant(x);
ExecutingUnrollUntilReturnTest.SpecialSideEffect5 += x;
ExecutingUnrollUntilReturnTest.SpecialSideEffect6 += x;
ExecutingUnrollUntilReturnTest.ExecutedSideEffect3 = 1024;
continue l3;
}
}
if (i3 == ExecutingUnrollUntilReturnTest.ExecutedSideEffect4) {
GraalDirectives.blackhole(CONTINUE_LOOP_MARKER);
CompilerAsserts.partialEvaluationConstant(i3);
int x = i3 + i1 + 2 + i2;
CompilerAsserts.partialEvaluationConstant(x);
ExecutingUnrollUntilReturnTest.SpecialSideEffect7 += x;
ExecutingUnrollUntilReturnTest.SpecialSideEffect8 += x;
ExecutingUnrollUntilReturnTest.ExecutedSideEffect4 = 1024;
continue l1;
}
if (i3 == ExecutingUnrollUntilReturnTest.ExecutedSideEffect5) {
GraalDirectives.blackhole(CONTINUE_LOOP_MARKER);
CompilerAsserts.partialEvaluationConstant(i3);
int x = i3 + i1 + 2 + i2;
CompilerAsserts.partialEvaluationConstant(x);
ExecutingUnrollUntilReturnTest.SpecialSideEffect9 += x;
ExecutingUnrollUntilReturnTest.SpecialSideEffect10 += x;
ExecutingUnrollUntilReturnTest.ExecutedSideEffect5 = 1024;
continue l2;
}
}
if (i2 == ExecutingUnrollUntilReturnTest.ExecutedSideEffect6) {
GraalDirectives.blackhole(CONTINUE_LOOP_MARKER);
CompilerAsserts.partialEvaluationConstant(i2);
int x = i2 + i1 + 2 + i2;
CompilerAsserts.partialEvaluationConstant(x);
ExecutingUnrollUntilReturnTest.SpecialSideEffect11 += x;
ExecutingUnrollUntilReturnTest.SpecialSideEffect12 += x;
ExecutingUnrollUntilReturnTest.ExecutedSideEffect6 = 1024;
continue l1;
}
}
}
GraalDirectives.blackhole(AFTER_LOOP_MARKER);
if (!CompilerDirectives.inCompiledCode()) {
ExecutingUnrollUntilReturnTest.interpretedInvocationCounts++;
} else {
ExecutingUnrollUntilReturnTest.compiledInvocationCounts++;
}
return ExecutingUnrollUntilReturnTest.result();
}
}
public class Unroll0 extends AbstractTestNode {
@ExplodeLoop(kind = LoopExplosionKind.FULL_UNROLL)
@Override
public int execute(VirtualFrame frame) {
int i = 0;
while (true) {
if (i >= count) {
// LEX 1 -> constant number of loop iterations
break;
}
GraalDirectives.blackhole(INSIDE_LOOP_MARKER);
SideEffect = i;
if (i == SideEffect2) {
// LEX 2 (1) -> continue OUTSIDE_LOOP_MARKER
/*
* Outside of the loop, duplicate for each unrolling until the return
*/
GraalDirectives.blackhole(OUTSIDE_LOOP_MARKER);
GraalDirectives.blackhole(i);
CompilerAsserts.partialEvaluationConstant(i);
return i;
}
if (i == SideEffect3) {
// LEN 1 -> continue at header
// that is the difference of unroll vs explode:unrolling will merge the ends,
// explode will duplicate the next loop iterations per loop end
i++;
continue;
}
if (i == SideEffect1) {
// LEX 3 (2) -> continue at AFTER_LOOP_MARKER
break;
}
i++;
// LEN 2 -> continue at header
}
GraalDirectives.blackhole(AFTER_LOOP_MARKER);
return count;
}
}
public class Unroll01 extends AbstractTestNode {
@ExplodeLoop(kind = LoopExplosionKind.FULL_UNROLL_UNTIL_RETURN)
@Override
public int execute(VirtualFrame frame) {
int i = 0;
while (true) {
if (i >= count) {
// LEX 1 -> constant number of loop iterations
break;
}
GraalDirectives.blackhole(INSIDE_LOOP_MARKER);
SideEffect = i;
if (i == SideEffect2) {
// LEX 2 (1) -> continue OUTSIDE_LOOP_MARKER
/*
* Outside of the loop, duplicate for each unrolling until the return
*/
GraalDirectives.blackhole(OUTSIDE_LOOP_MARKER);
GraalDirectives.blackhole(i);
CompilerAsserts.partialEvaluationConstant(i);
return i;
}
if (i == SideEffect3) {
// LEN 1 -> continue at header
// that is the difference of unroll vs explode:unrolling will merge the ends,
// explode will duplicate the next loop iterations per loop end
i++;
continue;
}
if (i == SideEffect1) {
// LEX 3 (2) -> continue at AFTER_LOOP_MARKER
break;
}
i++;
// LEN 2 -> continue at header
}
GraalDirectives.blackhole(AFTER_LOOP_MARKER);
return count;
}
}
public class Unroll02 extends AbstractTestNode {
@ExplodeLoop(kind = LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN)
@Override
public int execute(VirtualFrame frame) {
int i = 0;
while (true) {
if (i >= count) {
// LEX 1 -> constant number of loop iterations
break;
}
GraalDirectives.blackhole(INSIDE_LOOP_MARKER);
SideEffect = i;
if (i == SideEffect2) {
// LEX 2 -> continue OUTSIDE_LOOP_MARKER
/*
* Outside of the loop, duplicate for each unrolling until the return
*/
GraalDirectives.blackhole(OUTSIDE_LOOP_MARKER);
GraalDirectives.blackhole(i);
CompilerAsserts.partialEvaluationConstant(i);
return i;
}
if (i == SideEffect3) {
// LEN 1 -> continue at header
// that is the difference of unroll vs explode:unrolling will merge the ends,
// explode will duplicate the next loop iterations per loop end
i++;
continue;
}
if (i == SideEffect1) {
// LEX 3 -> continue at AFTER_LOOP_MARKER
break;
}
i++;
// LEN 2 -> continue at header
}
GraalDirectives.blackhole(AFTER_LOOP_MARKER);
return count;
}
}
}