From dfd3b54ee4d09dfb88e8787a09fcfef49fdd4d74 Mon Sep 17 00:00:00 2001 From: Dmitriy Dolovov Date: Fri, 19 Mar 2021 16:05:48 +0300 Subject: [PATCH] Native: Handle integer overflow on div/rem of Int.MIN_VALUE by -1 ^KT-45136 --- .../backend/konan/llvm/IntrinsicGenerator.kt | 54 +++++++++++++------ 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt index c3613e4438a..1ca324af79b 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt @@ -14,7 +14,6 @@ import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.types.getClass import org.jetbrains.kotlin.ir.util.dump import org.jetbrains.kotlin.ir.util.findAnnotation -import org.jetbrains.kotlin.ir.util.isSuspend internal enum class IntrinsicType { PLUS, @@ -630,27 +629,48 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv } private fun FunctionGenerationContext.emitSignedDiv(args: List): LLVMValueRef { - val (first, second) = args - if (!second.type.isFloatingPoint()) { - emitThrowIfZero(second) - } - return if (first.type.isFloatingPoint()) { - LLVMBuildFDiv(builder, first, second, "") + val (dividend, divisor) = args + val divisorType = divisor.type + return if (!divisorType.isFloatingPoint()) { + emitThrowIfZero(divisor) + emitSignedDivisionWithOverflow(dividend, divisor, divisorType, retZeroOnOverflow = false) { + LLVMBuildSDiv(builder, dividend, divisor, "")!! + } } else { - LLVMBuildSDiv(builder, first, second, "") - }!! + LLVMBuildFDiv(builder, dividend, divisor, "")!! + } } private fun FunctionGenerationContext.emitSignedRem(args: List): LLVMValueRef { - val (first, second) = args - if (!second.type.isFloatingPoint()) { - emitThrowIfZero(second) - } - return if (first.type.isFloatingPoint()) { - LLVMBuildFRem(builder, first, second, "") + val (dividend, divisor) = args + val divisorType = divisor.type + return if (!divisorType.isFloatingPoint()) { + emitThrowIfZero(divisor) + emitSignedDivisionWithOverflow(dividend, divisor, divisorType, retZeroOnOverflow = true) { + LLVMBuildSRem(builder, dividend, divisor, "")!! + } } else { - LLVMBuildSRem(builder, first, second, "") - }!! + LLVMBuildFRem(builder, dividend, divisor, "")!! + } + } + + private inline fun FunctionGenerationContext.emitSignedDivisionWithOverflow( + dividend: LLVMValueRef, + divisor: LLVMValueRef, + type: LLVMTypeRef, + retZeroOnOverflow: Boolean, + nonOverflowValue: () -> LLVMValueRef + ): LLVMValueRef { + val minValue = when (val sizeInBits = type.sizeInBits()) { + 32 -> LLVMConstInt(type, Int.MIN_VALUE.toLong(), 1)!! + 64 -> LLVMConstInt(type, Long.MIN_VALUE, 1)!! + else -> error("Unsupported signed integer division argument width: $sizeInBits") + } + + val minusOne = LLVMConstInt(type, -1, 1)!! + val overflowValue = if (retZeroOnOverflow) Zero(type).llvm else minValue + + return ifThenElse(and(icmpEq(dividend, minValue), icmpEq(divisor, minusOne)), overflowValue, nonOverflowValue) } private fun FunctionGenerationContext.emitUnsignedDiv(args: List): LLVMValueRef {