Skip to content

Commit

Permalink
boolToFpSort bug fix
Browse files Browse the repository at this point in the history
  • Loading branch information
zishkaz committed Sep 30, 2024
1 parent 6abe719 commit cbd2070
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 10 deletions.
32 changes: 28 additions & 4 deletions usvm-ts/src/main/kotlin/org/usvm/TSBinaryOperator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ sealed class TSBinaryOperator(
val onFp: TSContext.(UExpr<UFpSort>, UExpr<UFpSort>) -> UExpr<out USort> = shouldNotBeCalled,
val onRef: TSContext.(UExpr<UAddressSort>, UExpr<UAddressSort>) -> UExpr<out USort> = shouldNotBeCalled,
val desiredSort: TSContext.(USort, USort) -> USort = { _, _ -> error("Should not be called") },
val banSorts: TSContext.(UExpr<out USort>, UExpr<out USort>) -> Set<USort> = {_, _ -> emptySet() },
) {

object Eq : TSBinaryOperator(
Expand All @@ -24,6 +25,22 @@ sealed class TSBinaryOperator(
onFp = { lhs, rhs -> mkFpEqualExpr(lhs, rhs).not() },
onRef = { lhs, rhs -> lhs.neq(rhs) },
desiredSort = { lhs, _ -> lhs },
banSorts = { lhs, rhs ->
when {
lhs is TSWrappedValue ->
// rhs.sort == addressSort is a mock not to cause undefined
// behaviour with support of new language features.
if (rhs is TSWrappedValue || rhs.sort == addressSort) emptySet() else TSTypeSystem.primitiveTypes
.map(::typeToSort).toSet()
.minus(rhs.sort)
rhs is TSWrappedValue ->
// lhs.sort == addressSort explained as above.
if (lhs.sort == addressSort) emptySet() else TSTypeSystem.primitiveTypes
.map(::typeToSort).toSet()
.minus(lhs.sort)
else -> emptySet()
}
}
)

object Add : TSBinaryOperator(
Expand All @@ -46,13 +63,17 @@ sealed class TSBinaryOperator(
)

internal operator fun invoke(lhs: UExpr<out USort>, rhs: UExpr<out USort>, scope: TSStepScope): UExpr<out USort> {
val lhsSort = lhs.sort
val rhsSort = rhs.sort
val bannedSorts = lhs.tctx.banSorts(lhs, rhs)

fun apply(lhs: UExpr<out USort>, rhs: UExpr<out USort>): UExpr<out USort>? {
val ctx = lhs.tctx
if (ctx.desiredSort(lhs.sort, rhs.sort) != lhs.sort) return null
assert(lhs.sort == rhs.sort)
val lhsSort = lhs.sort
val rhsSort = rhs.sort
assert(lhsSort == rhsSort)

if (lhsSort in bannedSorts) return null
if (ctx.desiredSort(lhsSort, rhsSort) != lhsSort) return null

return when (lhs.sort) {
is UBoolSort -> ctx.onBool(lhs.cast(), rhs.cast())
is UBvSort -> ctx.onBv(lhs.cast(), rhs.cast())
Expand All @@ -62,6 +83,9 @@ sealed class TSBinaryOperator(
}
}

val lhsSort = lhs.sort
val rhsSort = rhs.sort

val ctx = lhs.tctx
val sort = ctx.desiredSort(lhsSort, rhsSort)

Expand Down
4 changes: 2 additions & 2 deletions usvm-ts/src/main/kotlin/org/usvm/TSExprTransformer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class TSExprTransformer(
*/
private fun generateAdditionalExprs(): List<UExpr<out USort>> = with(ctx) {
val newExpr = when (baseExpr.sort) {
addressSort -> addedExprCache.putOrNull(mkEq(asFp64(), boolToFpSort(asBool())))
addressSort -> addedExprCache.putOrNull(mkEq(fpToBoolSort(asFp64()), asBool()))
else -> null
}

Expand All @@ -101,7 +101,7 @@ class TSExprTransformer(
fun asBool(): UExpr<KBoolSort> = exprCache.getOrPut(ctx.boolSort) {
when (baseExpr.sort) {
ctx.boolSort -> baseExpr
ctx.fp64Sort -> with(ctx) { mkIte(mkFpEqualExpr(baseExpr.cast(), mkFp64(1.0)), mkTrue(), mkFalse()) }
ctx.fp64Sort -> ctx.fpToBoolSort(baseExpr.cast())
ctx.addressSort -> with(ctx) {
TSRefTransformer(ctx, boolSort).apply(baseExpr.cast()).cast()
}
Expand Down
8 changes: 7 additions & 1 deletion usvm-ts/src/main/kotlin/org/usvm/Utils.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.usvm

import io.ksmt.sort.KFp64Sort
import org.usvm.memory.ULValue
import org.usvm.memory.UWritableMemory

Expand All @@ -8,7 +9,12 @@ fun UWritableMemory<*>.write(ref: ULValue<*, *>, value: UExpr<*>) {
write(ref as ULValue<*, USort>, value as UExpr<USort>, value.uctx.trueExpr)
}

fun UContext<*>.boolToFpSort(expr: UExpr<UBoolSort>) = mkIte(expr, mkFp64(1.0), mkFp64(0.0))
// Built-in KContext.bvToBool has identical implementation.
fun UContext<*>.boolToFpSort(expr: UExpr<UBoolSort>) =
mkIte(expr, mkFp64(1.0), mkFp64(0.0))

fun UContext<*>.fpToBoolSort(expr: UExpr<KFp64Sort>) =
mkIte(mkFpEqualExpr(expr, mkFp64(0.0)), mkFalse(), mkTrue())

fun UExpr<*>.unwrapJoinedExpr(ctx: UContext<*>): UExpr<out USort> =
if (this is UJoinedBoolExpr) ctx.mkAnd(exprs) else this
Expand Down
10 changes: 7 additions & 3 deletions usvm-ts/src/test/resources/samples/TypeCoercion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,14 @@ class TypeCoercion {
transitiveCoercionNoTypes(a, b, c): number {
// @ts-ignore
if (a == b) {
if (c && (a == c)) {
return 1
if (c != 0 && c != 1) {
if (c && (a == c)) {
return 1
} else {
return 2
}
} else {
return 2
return 4
}
}

Expand Down

0 comments on commit cbd2070

Please sign in to comment.