Intrinsics for 'reversed': array.indices
#KT-21323 In Progress
This commit is contained in:
@@ -19,14 +19,17 @@ package org.jetbrains.kotlin.codegen.range
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.codegen.generateCallReceiver
|
||||
import org.jetbrains.kotlin.codegen.range.forLoop.ForInDefinitelySafeSimpleProgressionLoopGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.forLoop.ForInSimpleProgressionLoopGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.forLoop.ForLoopGenerator
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
|
||||
class ArrayIndicesRangeValue(rangeCall: ResolvedCall<out CallableDescriptor>): PrimitiveNumberRangeIntrinsicRangeValue(rangeCall) {
|
||||
class ArrayIndicesRangeValue(rangeCall: ResolvedCall<out CallableDescriptor>) :
|
||||
PrimitiveNumberRangeIntrinsicRangeValue(rangeCall), ReversableRangeValue {
|
||||
|
||||
private val expectedReceiverType: KotlinType = ExpressionCodegen.getExpectedReceiverType(rangeCall)
|
||||
|
||||
@@ -44,4 +47,9 @@ class ArrayIndicesRangeValue(rangeCall: ResolvedCall<out CallableDescriptor>): P
|
||||
|
||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||
ForInSimpleProgressionLoopGenerator.fromBoundedValueWithStep1(codegen, forExpression, getBoundedValue(codegen))
|
||||
|
||||
override fun createForInReversedLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression): ForLoopGenerator =
|
||||
ForInDefinitelySafeSimpleProgressionLoopGenerator.fromBoundedValueWithStepMinus1(
|
||||
codegen, forExpression, getBoundedValue(codegen)
|
||||
)
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* 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.jetbrains.kotlin.codegen.range.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.codegen.range.SimpleBoundedValue
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
|
||||
/**
|
||||
* Generates "naive" for loop:
|
||||
*
|
||||
* ```
|
||||
* i = [| startValue |];
|
||||
* [| if (!isStartInclusive) inc i |];
|
||||
* end = [| endValue |];
|
||||
* while ([| cmp(i, end) |]) ... {
|
||||
* [| body |];
|
||||
* inc i;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* This generator is suitable for cases where arithmetic overflow is impossible.
|
||||
*/
|
||||
class ForInDefinitelySafeSimpleProgressionLoopGenerator(
|
||||
codegen: ExpressionCodegen,
|
||||
forExpression: KtForExpression,
|
||||
private val startValue: StackValue,
|
||||
private val isStartInclusive: Boolean,
|
||||
private val endValue: StackValue,
|
||||
private val isEndInclusive: Boolean,
|
||||
step: Int
|
||||
) : AbstractForInRangeLoopGenerator(codegen, forExpression, step) {
|
||||
|
||||
constructor(
|
||||
codegen: ExpressionCodegen,
|
||||
forExpression: KtForExpression,
|
||||
boundedValue: SimpleBoundedValue,
|
||||
step: Int
|
||||
) : this(
|
||||
codegen, forExpression,
|
||||
startValue = if (step == 1) boundedValue.lowBound else boundedValue.highBound,
|
||||
isStartInclusive = if (step == 1) boundedValue.isLowInclusive else boundedValue.isHighInclusive,
|
||||
endValue = if (step == 1) boundedValue.highBound else boundedValue.lowBound,
|
||||
isEndInclusive = if (step == 1) boundedValue.isHighInclusive else boundedValue.isLowInclusive,
|
||||
step = step
|
||||
)
|
||||
|
||||
companion object {
|
||||
fun fromBoundedValueWithStep1(codegen: ExpressionCodegen, forExpression: KtForExpression, boundedValue: SimpleBoundedValue) =
|
||||
ForInDefinitelySafeSimpleProgressionLoopGenerator(codegen, forExpression, boundedValue, 1)
|
||||
|
||||
fun fromBoundedValueWithStepMinus1(codegen: ExpressionCodegen, forExpression: KtForExpression, boundedValue: SimpleBoundedValue) =
|
||||
ForInDefinitelySafeSimpleProgressionLoopGenerator(codegen, forExpression, boundedValue, -1)
|
||||
}
|
||||
|
||||
override fun storeRangeStartAndEnd() {
|
||||
loopParameter().store(startValue, v)
|
||||
// Skip 1st element if start is not inclusive.
|
||||
if (!isStartInclusive) incrementLoopVariable()
|
||||
|
||||
StackValue.local(endVar, asmElementType).store(endValue, v)
|
||||
}
|
||||
|
||||
override fun checkEmptyLoop(loopExit: Label) {
|
||||
}
|
||||
|
||||
override fun checkPreCondition(loopExit: Label) {
|
||||
loopParameter().put(asmElementType, v)
|
||||
v.load(endVar, asmElementType)
|
||||
if (asmElementType.sort == Type.LONG) {
|
||||
v.lcmp()
|
||||
if (step > 0) {
|
||||
if (isEndInclusive) {
|
||||
v.ifgt(loopExit)
|
||||
}
|
||||
else {
|
||||
v.ifge(loopExit)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (isEndInclusive) {
|
||||
v.iflt(loopExit)
|
||||
}
|
||||
else {
|
||||
v.ifle(loopExit)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (step > 0) {
|
||||
if (isEndInclusive) {
|
||||
v.ificmpgt(loopExit)
|
||||
}
|
||||
else {
|
||||
v.ificmpge(loopExit)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (isEndInclusive) {
|
||||
v.ificmplt(loopExit)
|
||||
}
|
||||
else {
|
||||
v.ificmple(loopExit)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun checkPostConditionAndIncrement(loopExit: Label) {
|
||||
incrementLoopVariable()
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// WITH_RUNTIME
|
||||
import kotlin.test.*
|
||||
|
||||
fun box(): String {
|
||||
val arr = intArrayOf(1, 1, 1, 1)
|
||||
var sum = 0
|
||||
for (i in arr.indices.reversed()) {
|
||||
sum = sum * 10 + i + arr[i]
|
||||
}
|
||||
assertEquals(4321, sum)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// WITH_RUNTIME
|
||||
import kotlin.test.*
|
||||
|
||||
fun box(): String {
|
||||
val arr = intArrayOf(1, 1, 1, 1)
|
||||
var sum = 0
|
||||
for (i in arr.indices.reversed()) {
|
||||
sum = sum * 10 + i + arr[i]
|
||||
}
|
||||
assertEquals(4321, sum)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
// 0 reversed
|
||||
+6
@@ -15241,6 +15241,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/forInReversed"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedArrayIndices.kt")
|
||||
public void testForInReversedArrayIndices() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedArrayIndices.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedEmptyRange.kt")
|
||||
public void testForInReversedEmptyRange() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedEmptyRange.kt");
|
||||
|
||||
@@ -15241,6 +15241,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/forInReversed"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedArrayIndices.kt")
|
||||
public void testForInReversedArrayIndices() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedArrayIndices.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedEmptyRange.kt")
|
||||
public void testForInReversedEmptyRange() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedEmptyRange.kt");
|
||||
|
||||
@@ -1408,6 +1408,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/forLoop/forInReversed"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedArrayIndices.kt")
|
||||
public void testForInReversedArrayIndices() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/forLoop/forInReversed/forInReversedArrayIndices.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedEmptyRangeLiteral.kt")
|
||||
public void testForInReversedEmptyRangeLiteral() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/forLoop/forInReversed/forInReversedEmptyRangeLiteral.kt");
|
||||
|
||||
@@ -15241,6 +15241,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/forInReversed"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedArrayIndices.kt")
|
||||
public void testForInReversedArrayIndices() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedArrayIndices.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedEmptyRange.kt")
|
||||
public void testForInReversedEmptyRange() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedEmptyRange.kt");
|
||||
|
||||
@@ -16657,6 +16657,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/forInReversed"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedArrayIndices.kt")
|
||||
public void testForInReversedArrayIndices() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedArrayIndices.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("forInReversedEmptyRange.kt")
|
||||
public void testForInReversedEmptyRange() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedEmptyRange.kt");
|
||||
|
||||
Reference in New Issue
Block a user