Native: Handle integer overflow on div/rem of Int.MIN_VALUE by -1

^KT-45136
This commit is contained in:
Dmitriy Dolovov
2021-03-19 16:05:48 +03:00
parent 7fe0df2816
commit dfd3b54ee4
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.types.getClass import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.util.dump import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.findAnnotation import org.jetbrains.kotlin.ir.util.findAnnotation
import org.jetbrains.kotlin.ir.util.isSuspend
internal enum class IntrinsicType { internal enum class IntrinsicType {
PLUS, PLUS,
@@ -630,27 +629,48 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
} }
private fun FunctionGenerationContext.emitSignedDiv(args: List<LLVMValueRef>): LLVMValueRef { private fun FunctionGenerationContext.emitSignedDiv(args: List<LLVMValueRef>): LLVMValueRef {
val (first, second) = args val (dividend, divisor) = args
if (!second.type.isFloatingPoint()) { val divisorType = divisor.type
emitThrowIfZero(second) return if (!divisorType.isFloatingPoint()) {
} emitThrowIfZero(divisor)
return if (first.type.isFloatingPoint()) { emitSignedDivisionWithOverflow(dividend, divisor, divisorType, retZeroOnOverflow = false) {
LLVMBuildFDiv(builder, first, second, "") LLVMBuildSDiv(builder, dividend, divisor, "")!!
}
} else { } else {
LLVMBuildSDiv(builder, first, second, "") LLVMBuildFDiv(builder, dividend, divisor, "")!!
}!! }
} }
private fun FunctionGenerationContext.emitSignedRem(args: List<LLVMValueRef>): LLVMValueRef { private fun FunctionGenerationContext.emitSignedRem(args: List<LLVMValueRef>): LLVMValueRef {
val (first, second) = args val (dividend, divisor) = args
if (!second.type.isFloatingPoint()) { val divisorType = divisor.type
emitThrowIfZero(second) return if (!divisorType.isFloatingPoint()) {
} emitThrowIfZero(divisor)
return if (first.type.isFloatingPoint()) { emitSignedDivisionWithOverflow(dividend, divisor, divisorType, retZeroOnOverflow = true) {
LLVMBuildFRem(builder, first, second, "") LLVMBuildSRem(builder, dividend, divisor, "")!!
}
} else { } 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>): LLVMValueRef { private fun FunctionGenerationContext.emitUnsignedDiv(args: List<LLVMValueRef>): LLVMValueRef {