From a4b8ab819930639de6ae3323af6704536c08f62c Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Fri, 23 Jun 2023 10:56:15 +0200 Subject: [PATCH] [Native] Forbid to inline NaN values during const evaluation --- .../kotlin/ir/interpreter/IrInterpreterConfiguration.kt | 2 ++ .../ir/interpreter/checker/IrInterpreterCommonChecker.kt | 8 ++++++++ .../kotlin/backend/konan/driver/phases/Lowerings.kt | 8 +++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreterConfiguration.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreterConfiguration.kt index 187aef56f51..0a181e07777 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreterConfiguration.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreterConfiguration.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.platform.TargetPlatform * 'true' - interpreter will construct object and initialize its properties despite the fact it is not marked as compile time; * 'false' - interpreter will create a representation of empty object, that can be used to get const properties * @param inlineConstVal tell the interpreter that value of const property can be inlined instead of getter call + * @param inlineNanVal allows to inline values of `Double.NaN` and `Float.NaN` */ // TODO maybe create some sort of builder data class IrInterpreterConfiguration( @@ -25,4 +26,5 @@ data class IrInterpreterConfiguration( val printOnlyExceptionMessage: Boolean = false, val collapseStackTraceFromJDK: Boolean = true, val inlineConstVal: Boolean = true, + val inlineNanVal: Boolean = true, ) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterCommonChecker.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterCommonChecker.kt index e467eaae257..2280ef99422 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterCommonChecker.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterCommonChecker.kt @@ -116,7 +116,15 @@ class IrInterpreterCommonChecker : IrInterpreterChecker { return body.kind == IrSyntheticBodyKind.ENUM_VALUES || body.kind == IrSyntheticBodyKind.ENUM_VALUEOF } + private fun IrConst<*>.isNaN(): Boolean { + return this.kind == IrConstKind.Double && IrConstKind.Double.valueOf(this).isNaN() || + this.kind == IrConstKind.Float && IrConstKind.Float.valueOf(this).isNaN() + } + override fun visitConst(expression: IrConst<*>, data: IrInterpreterCheckerData): Boolean { + if (!data.interpreterConfiguration.inlineNanVal) { + return !expression.isNaN() + } return true } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Lowerings.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Lowerings.kt index d3900b309b8..233e1290690 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Lowerings.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Lowerings.kt @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.backend.konan.lower.UnboxInlineLowering import org.jetbrains.kotlin.backend.konan.optimizations.KonanBCEForLoopBodyTransformer import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid @@ -493,7 +494,12 @@ private val objectClassesPhase = createFileLoweringPhase( ) private val constEvaluationPhase = createFileLoweringPhase( - lowering = ::ConstEvaluationLowering, + lowering = { context: Context -> + // NaN constants has inconsistencies between IR and metadata representation, + // so inlining them can lead to incorrect behaviour. Check KT-53258 for details. + val configuration = IrInterpreterConfiguration(printOnlyExceptionMessage = true, inlineNanVal = false) + ConstEvaluationLowering(context, configuration = configuration) + }, name = "ConstEvaluationLowering", description = "Evaluate functions that are marked as `IntrinsicConstEvaluation`", prerequisite = setOf(inlinePhase)