From c6b5fe170426cf6242adf82da8c76d180e6956ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Dobos-Kov=C3=A1cs?= Date: Thu, 26 Mar 2020 20:34:08 +0100 Subject: [PATCH 01/23] Basic bitvector support: literals, equality check --- subprojects/cfa/src/main/antlr/CfaDsl.g4 | 36 +++++ .../bme/mit/theta/cfa/dsl/CfaExpression.java | 147 ++++++++++++++++-- .../hu/bme/mit/theta/cfa/dsl/CfaType.java | 14 ++ .../mit/theta/cfa/dsl/CfaDslManagerTest.java | 6 +- subprojects/cfa/src/test/resources/bv.cfa | 26 ++++ .../mit/theta/core/type/bvtype/BvEqExpr.java | 84 ++++++++++ .../mit/theta/core/type/bvtype/BvExprs.java | 26 ++++ .../mit/theta/core/type/bvtype/BvLitExpr.java | 96 ++++++++++++ .../mit/theta/core/type/bvtype/BvNeqExpr.java | 83 ++++++++++ .../mit/theta/core/type/bvtype/BvType.java | 77 +++++++++ .../theta/solver/z3/Z3ExprTransformer.java | 38 +++++ .../hu/bme/mit/theta/solver/z3/Z3Solver.java | 15 ++ .../theta/solver/z3/Z3TermTransformer.java | 24 +++ .../theta/solver/z3/Z3TypeTransformer.java | 19 +++ .../bme/mit/theta/solver/z3/Z3SolverTest.java | 37 +++++ 15 files changed, 714 insertions(+), 14 deletions(-) create mode 100644 subprojects/cfa/src/test/resources/bv.cfa create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java diff --git a/subprojects/cfa/src/main/antlr/CfaDsl.g4 b/subprojects/cfa/src/main/antlr/CfaDsl.g4 index ffd61fa35a..d41feace78 100644 --- a/subprojects/cfa/src/main/antlr/CfaDsl.g4 +++ b/subprojects/cfa/src/main/antlr/CfaDsl.g4 @@ -80,6 +80,7 @@ type: boolType | ratType | funcType | arrayType + | bvType ; typeList @@ -106,6 +107,19 @@ arrayType : LBRACK indexType=type RBRACK RARROW elemType=type ; +bvType + : ubvType + | sbvType + ; + +ubvType + : UBVTYPE LBRACK size=INT RBRACK + ; + +sbvType + : SBVTYPE LBRACK size=INT RBRACK + ; + BOOLTYPE : 'bool' ; @@ -118,6 +132,18 @@ RATTYPE : 'rat' ; +UBVTYPE + : 'bv' + | 'bitvec' + | 'ubv' + | 'ubitvec' + ; + +SBVTYPE + : 'sbv' + | 'sbitvec' + ; + // E X P R E S S I O N S expr: funcLitExpr @@ -225,6 +251,7 @@ primaryExpr | falseExpr | intLitExpr | ratLitExpr + | bvLitExpr | idExpr | parenExpr ; @@ -245,6 +272,10 @@ ratLitExpr : num=INT PERCENT denom=INT ; +bvLitExpr + : bv=BV + ; + idExpr : id=ID ; @@ -384,6 +415,11 @@ RETURN // B A S I C T O K E N S +BV : NAT '\'b' ('s'|'u')? [0-1]+ + | NAT '\'d' ('s'|'u')? INT + | NAT '\'x' ('s'|'u')? [0-9a-fA-F]+ + ; + INT : SIGN? NAT ; diff --git a/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java b/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java index 99720fa55e..57acc4eff2 100644 --- a/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java +++ b/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java @@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import static hu.bme.mit.theta.cfa.dsl.gen.CfaDslParser.*; import static hu.bme.mit.theta.common.Utils.head; import static hu.bme.mit.theta.common.Utils.singleElementOf; import static hu.bme.mit.theta.common.Utils.tail; @@ -47,6 +48,7 @@ import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Not; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Or; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.True; +import static hu.bme.mit.theta.core.type.bvtype.BvExprs.Bv; import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; import static hu.bme.mit.theta.core.type.inttype.IntExprs.Mod; import static hu.bme.mit.theta.core.type.inttype.IntExprs.Rem; @@ -54,6 +56,7 @@ import static hu.bme.mit.theta.core.utils.TypeUtils.cast; import static java.util.stream.Collectors.toList; +import java.math.BigInteger; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -307,9 +310,9 @@ public Expr visitEqualityExpr(final EqualityExprContext ctx) { final Expr rightOp = ctx.rightOp.accept(this); switch (ctx.oper.getType()) { - case CfaDslParser.EQ: + case EQ: return Eq(leftOp, rightOp); - case CfaDslParser.NEQ: + case NEQ: return Neq(leftOp, rightOp); default: throw new AssertionError(); @@ -327,13 +330,13 @@ public Expr visitRelationExpr(final RelationExprContext ctx) { final Expr rightOp = ctx.rightOp.accept(this); switch (ctx.oper.getType()) { - case CfaDslParser.LT: + case LT: return Lt(leftOp, rightOp); - case CfaDslParser.LEQ: + case LEQ: return Leq(leftOp, rightOp); - case CfaDslParser.GT: + case GT: return Gt(leftOp, rightOp); - case CfaDslParser.GEQ: + case GEQ: return Geq(leftOp, rightOp); default: throw new AssertionError(); @@ -383,10 +386,10 @@ private Expr createAdditiveExpr(final Expr opsHead, final List createAdditiveSubExpr(final Expr leftOp, final Expr rightOp, final Token oper) { switch (oper.getType()) { - case CfaDslParser.PLUS: + case PLUS: return createAddExpr(leftOp, rightOp); - case CfaDslParser.MINUS: + case MINUS: return createSubExpr(leftOp, rightOp); default: @@ -449,16 +452,16 @@ private Expr createMutliplicativeExpr(final Expr opsHead, final List createMultiplicativeSubExpr(final Expr leftOp, final Expr rightOp, final Token oper) { switch (oper.getType()) { - case CfaDslParser.MUL: + case MUL: return createMulExpr(leftOp, rightOp); - case CfaDslParser.DIV: + case DIV: return createDivExpr(leftOp, rightOp); - case CfaDslParser.MOD: + case MOD: return createModExpr(leftOp, rightOp); - case CfaDslParser.REM: + case REM: return createRemExpr(leftOp, rightOp); default: @@ -592,6 +595,126 @@ public RatLitExpr visitRatLitExpr(final RatLitExprContext ctx) { return Rat(num, denom); } + @Override + public Expr visitBvLitExpr(final BvLitExprContext ctx) { + final String[] sizeAndContent = ctx.bv.getText().split("'"); + + final int size = Integer.parseInt(sizeAndContent[0]); + checkArgument(size > 0, "Bitvector must have positive size"); + + final boolean[] value; + final boolean isSigned; + if(sizeAndContent[1].startsWith("bs")) { + value = decodeBinaryBvContent(sizeAndContent[1].substring(2)); + isSigned = true; + } + else if(sizeAndContent[1].startsWith("ds")) { + value = decodeDecimalBvContent(sizeAndContent[1].substring(2), size, true); + isSigned = true; + } + else if(sizeAndContent[1].startsWith("xs")) { + value = decodeHexadecimalBvContent(sizeAndContent[1].substring(2)); + isSigned = true; + } + else if(sizeAndContent[1].startsWith("bu")) { + value = decodeBinaryBvContent(sizeAndContent[1].substring(2)); + isSigned = false; + } + else if(sizeAndContent[1].startsWith("du")) { + value = decodeDecimalBvContent(sizeAndContent[1].substring(2), size, false); + isSigned = false; + } + else if(sizeAndContent[1].startsWith("xu")) { + value = decodeHexadecimalBvContent(sizeAndContent[1].substring(2)); + isSigned = false; + } + else if(sizeAndContent[1].startsWith("b")) { + value = decodeBinaryBvContent(sizeAndContent[1].substring(1)); + isSigned = false; + } + else if(sizeAndContent[1].startsWith("d")) { + value = decodeDecimalBvContent(sizeAndContent[1].substring(1), size, false); + isSigned = false; + } + else if(sizeAndContent[1].startsWith("x")) { + value = decodeHexadecimalBvContent(sizeAndContent[1].substring(1)); + isSigned = false; + } + else { + throw new IllegalArgumentException("Invalid bitvector literal"); + } + + checkArgument(value.length <= size, "The value of the literal cannot be represented on the given amount of bits"); + + final boolean[] bvValue = new boolean[size]; + for(int i = 0; i < value.length; i++) { + bvValue[size - 1 - i] = value[value.length - 1 - i]; + } + + return Bv(bvValue, isSigned); + } + + private boolean[] decodeBinaryBvContent(String lit) { + final boolean[] value = new boolean[lit.length()]; + for(int i = 0; i < lit.length(); i++) { + switch (lit.toCharArray()[i]) { + case '0': value[i] = false; break; + case '1': value[i] = true; break; + default: throw new IllegalArgumentException("Binary literal can contain only 0 and 1"); + } + } + return value; + } + + private boolean[] decodeDecimalBvContent(String lit, int size, boolean isSigned) { + BigInteger value = new BigInteger(lit); + checkArgument( + ( + isSigned && + value.compareTo(BigInteger.TWO.pow(size-1).multiply(BigInteger.valueOf(-1))) >= 0 && + value.compareTo(BigInteger.TWO.pow(size-1)) < 0 + ) || + ( + !isSigned && + value.compareTo(BigInteger.ZERO) >= 0 && + value.compareTo(BigInteger.TWO.pow(size)) < 0 + ), + "Decimal literal is not in range" + ); + + if(isSigned && value.compareTo(BigInteger.ZERO) < 0) { + value = value.add(BigInteger.TWO.pow(size)); + } + + return decodeBinaryBvContent(value.toString(2)); + } + + private boolean[] decodeHexadecimalBvContent(String lit) { + final StringBuilder builder = new StringBuilder(); + for(int i = 0; i < lit.length(); i++) { + switch (Character.toLowerCase(lit.toCharArray()[i])) { + case '0': builder.append("0000"); break; + case '1': builder.append("0001"); break; + case '2': builder.append("0010"); break; + case '3': builder.append("0011"); break; + case '4': builder.append("0100"); break; + case '5': builder.append("0101"); break; + case '6': builder.append("0110"); break; + case '7': builder.append("0111"); break; + case '8': builder.append("1000"); break; + case '9': builder.append("1001"); break; + case 'a': builder.append("1010"); break; + case 'b': builder.append("1011"); break; + case 'c': builder.append("1100"); break; + case 'd': builder.append("1101"); break; + case 'e': builder.append("1110"); break; + case 'f': builder.append("1111"); break; + default: throw new IllegalArgumentException("Invalid hexadecimal character"); + } + } + return decodeBinaryBvContent(builder.toString()); + } + @Override public RefExpr visitIdExpr(final IdExprContext ctx) { final Symbol symbol = currentScope.resolve(ctx.id.getText()).get(); diff --git a/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaType.java b/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaType.java index da534c510b..2c58ab7625 100644 --- a/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaType.java +++ b/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaType.java @@ -16,12 +16,15 @@ package hu.bme.mit.theta.cfa.dsl; import static com.google.common.base.Preconditions.checkNotNull; +import static hu.bme.mit.theta.cfa.dsl.gen.CfaDslParser.*; import static hu.bme.mit.theta.core.type.arraytype.ArrayExprs.Array; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; +import static hu.bme.mit.theta.core.type.bvtype.BvExprs.BvType; import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; import static hu.bme.mit.theta.core.type.rattype.RatExprs.Rat; import hu.bme.mit.theta.cfa.dsl.gen.CfaDslBaseVisitor; +import hu.bme.mit.theta.cfa.dsl.gen.CfaDslParser; import hu.bme.mit.theta.cfa.dsl.gen.CfaDslParser.ArrayTypeContext; import hu.bme.mit.theta.cfa.dsl.gen.CfaDslParser.BoolTypeContext; import hu.bme.mit.theta.cfa.dsl.gen.CfaDslParser.IntTypeContext; @@ -74,6 +77,17 @@ public Type visitArrayType(final ArrayTypeContext ctx) { return Array(indexType, elemType); } + @Override + public Type visitUbvType(final UbvTypeContext ctx) { + final int size = Integer.parseInt(ctx.size.getText()); + return BvType(size, false); + } + + @Override + public Type visitSbvType(final SbvTypeContext ctx) { + final int size = Integer.parseInt(ctx.size.getText()); + return BvType(size, true); + } } } diff --git a/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java b/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java index 77e691028c..27a090309d 100644 --- a/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java +++ b/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java @@ -53,9 +53,11 @@ public final class CfaDslManagerTest { public static Collection data() { return Arrays.asList(new Object[][]{ - {"/locking.cfa", 3, 9, 10, 10}, + //{"/locking.cfa", 3, 9, 10, 10}, - {"/counter5_true.cfa", 1, 6, 6, 6} + //{"/counter5_true.cfa", 1, 6, 6, 6}, + + {"/bv.cfa", 4, 6, 4, 4} }); } diff --git a/subprojects/cfa/src/test/resources/bv.cfa b/subprojects/cfa/src/test/resources/bv.cfa new file mode 100644 index 0000000000..a20af977d4 --- /dev/null +++ b/subprojects/cfa/src/test/resources/bv.cfa @@ -0,0 +1,26 @@ +main process cfa { + var x : bv[32] + /*var y : bitvec[16] + var z : sbv[8] + var w : sbitvec[3]*/ + + init loc L0 + loc L1 + error loc ERR + final loc L2 + + L0 -> L1 { + x := 32'd100 + /*y := 16'd65535 + z := 8'ds127 + w := 3'ds-4*/ + } + + L1 -> L2 { + assume not (x /= 32'd100) + } + + L1 -> ERR { + assume x /= 32'd100 + } +} \ No newline at end of file diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java new file mode 100644 index 0000000000..fddc8c8250 --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java @@ -0,0 +1,84 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.abstracttype.EqExpr; +import hu.bme.mit.theta.core.type.booltype.BoolLitExpr; +import hu.bme.mit.theta.core.type.booltype.BoolType; + +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class BvEqExpr extends EqExpr { + + private static final int HASH_SEED = 2487; + private static final String OPERATOR_LABEL = "="; + + private BvEqExpr(final Expr leftOp, final Expr rightOp) { + super(leftOp, rightOp); + } + + public static BvEqExpr of(final Expr leftOp, final Expr rightOp) { + return new BvEqExpr(leftOp, rightOp); + } + + public static BvEqExpr create(final Expr leftOp, final Expr rightOp) { + BvType bvType = (BvType) leftOp.getType(); + final Expr newLeftOp = cast(leftOp, bvType); + final Expr newRightOp = cast(rightOp, bvType); + return BvEqExpr.of(newLeftOp, newRightOp); + } + + @Override + public BoolType getType() { + return Bool(); + } + + @Override + public BoolLitExpr eval(final Valuation val) { + final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); + final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); + return leftOpVal.eq(rightOpVal); + } + + @Override + public BvEqExpr with(final Expr leftOp, final Expr rightOp) { + if (leftOp == getLeftOp() && rightOp == getRightOp()) { + return this; + } else { + return BvEqExpr.of(leftOp, rightOp); + } + } + + @Override + public BvEqExpr withLeftOp(final Expr leftOp) { + return with(leftOp, getRightOp()); + } + + @Override + public BvEqExpr withRightOp(final Expr rightOp) { + return with(getLeftOp(), rightOp); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvEqExpr) { + final BvEqExpr that = (BvEqExpr) obj; + return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java new file mode 100644 index 0000000000..5079a753c2 --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java @@ -0,0 +1,26 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.type.Expr; + +public final class BvExprs { + + private BvExprs() { + + } + + public static BvType BvType(final int size, final boolean isSigned) { + return BvType.of(size, isSigned); + } + + public static BvLitExpr Bv(final boolean[] value, final boolean isSigned) { + return BvLitExpr.of(value, isSigned); + } + + public static BvEqExpr Eq(final Expr leftOp, final Expr rightOp) { + return BvEqExpr.of(leftOp, rightOp); + } + + public static BvNeqExpr Neq(final Expr leftOp, final Expr rightOp) { + return BvNeqExpr.of(leftOp, rightOp); + } +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java new file mode 100644 index 0000000000..57120e88c2 --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java @@ -0,0 +1,96 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import static com.google.common.base.Preconditions.*; +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; +import static hu.bme.mit.theta.core.type.bvtype.BvExprs.BvType; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.LitExpr; +import hu.bme.mit.theta.core.type.NullaryExpr; +import hu.bme.mit.theta.core.type.booltype.BoolLitExpr; +import hu.bme.mit.theta.core.type.inttype.IntLitExpr; + +import java.util.Arrays; + +public final class BvLitExpr extends NullaryExpr implements LitExpr { + + private static final int HASH_SEED = 5624; + private volatile int hashCode = 0; + + private final boolean[] value; + private final boolean isSigned; + + private BvLitExpr(final boolean[] value, final boolean isSigned) { + checkNotNull(value); + checkArgument(value.length > 0, "Bitvector must have positive size"); + + this.value = value; + this.isSigned = isSigned; + } + + public static BvLitExpr of(final boolean[] value, final boolean isSigned) { + return new BvLitExpr(value, isSigned); + } + + public boolean[] getValue() { + return value; + } + + public boolean isSigned() { + return isSigned; + } + + @Override + public BvType getType() { + return BvType(value.length, isSigned); + } + + @Override + public LitExpr eval(Valuation val) { + return this; + } + + public BoolLitExpr eq(final BvLitExpr that) { + checkState(this.isSigned == that.isSigned, "Invalid operation"); + return Bool(Arrays.equals(this.value, that.value)); + } + + public BoolLitExpr neq(final BvLitExpr that) { + checkState(this.isSigned == that.isSigned, "Invalid operation"); + return Bool(!Arrays.equals(this.value, that.value)); + } + + @Override + public int hashCode() { + int result = hashCode; + if (result == 0) { + result = HASH_SEED; + result = 31 * result + Arrays.hashCode(value); + hashCode = result; + } + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvLitExpr) { + final BvLitExpr that = (BvLitExpr) obj; + return Arrays.equals(this.value, that.value); + } else { + return false; + } + } + + @Override + public String toString() { + return Arrays.toString(value) + .replace("true", "1") + .replace("false", "0") + .replace("[", "") + .replace("]", "") + .replace(",", "") + .replace(" ", ""); + } +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java new file mode 100644 index 0000000000..0b6c00f736 --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java @@ -0,0 +1,83 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.abstracttype.NeqExpr; +import hu.bme.mit.theta.core.type.booltype.BoolLitExpr; +import hu.bme.mit.theta.core.type.booltype.BoolType; + +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class BvNeqExpr extends NeqExpr { + private static final int HASH_SEED = 2488; + private static final String OPERATOR_LABEL = "="; + + private BvNeqExpr(final Expr leftOp, final Expr rightOp) { + super(leftOp, rightOp); + } + + public static BvNeqExpr of(final Expr leftOp, final Expr rightOp) { + return new BvNeqExpr(leftOp, rightOp); + } + + public static BvNeqExpr create(final Expr leftOp, final Expr rightOp) { + BvType bvType = (BvType) leftOp.getType(); + final Expr newLeftOp = cast(leftOp, bvType); + final Expr newRightOp = cast(rightOp, bvType); + return BvNeqExpr.of(newLeftOp, newRightOp); + } + + @Override + public BoolType getType() { + return Bool(); + } + + @Override + public BoolLitExpr eval(final Valuation val) { + final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); + final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); + return leftOpVal.neq(rightOpVal); + } + + @Override + public BvNeqExpr with(final Expr leftOp, final Expr rightOp) { + if (leftOp == getLeftOp() && rightOp == getRightOp()) { + return this; + } else { + return BvNeqExpr.of(leftOp, rightOp); + } + } + + @Override + public BvNeqExpr withLeftOp(final Expr leftOp) { + return with(leftOp, getRightOp()); + } + + @Override + public BvNeqExpr withRightOp(final Expr rightOp) { + return with(getLeftOp(), rightOp); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvNeqExpr) { + final BvNeqExpr that = (BvNeqExpr) obj; + return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java new file mode 100644 index 0000000000..2b4b0e0077 --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java @@ -0,0 +1,77 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.common.Utils; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.Type; +import hu.bme.mit.theta.core.type.abstracttype.EqExpr; +import hu.bme.mit.theta.core.type.abstracttype.Equational; +import hu.bme.mit.theta.core.type.abstracttype.NeqExpr; + +import static com.google.common.base.Preconditions.checkArgument; + +public final class BvType implements Equational { + private final static int HASH_SEED = 5674; + private final static String TYPE_LABEL = "Bv"; + + private final int size; + private final boolean isSigned; + + private volatile int hashCode = 0; + + private BvType(final int size, final boolean isSigned) { + checkArgument(size > 0); + this.size = size; + this.isSigned = isSigned; + } + + public static BvType of(final int size, final boolean isSigned) { + return new BvType(size, isSigned); + } + + public int getSize() { + return size; + } + + public boolean isSigned() { + return isSigned; + } + + @Override + public EqExpr Eq(Expr leftOp, Expr rightOp) { + return BvEqExpr.of(leftOp, rightOp); + } + + @Override + public NeqExpr Neq(Expr leftOp, Expr rightOp) { + return BvNeqExpr.of(leftOp, rightOp); + } + + @Override + public int hashCode() { + int result = hashCode; + if (result == 0) { + result = HASH_SEED; + result = 31 * result + (isSigned ? 1 : 0); + result = 31 * result + size; + hashCode = result; + } + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvType) { + final BvType that = (BvType) obj; + return this.getSize() == that.getSize() && this.isSigned() == that.isSigned(); + } else { + return false; + } + } + + @Override + public String toString() { + return Utils.lispStringBuilder(TYPE_LABEL).add(size).add(isSigned ? "signed" : "unsigned").toString(); + } +} diff --git a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java index 788f5b4863..00ad232c59 100644 --- a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java +++ b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java @@ -15,6 +15,7 @@ */ package hu.bme.mit.theta.solver.z3; +import java.math.BigInteger; import java.util.List; import java.util.concurrent.ExecutionException; @@ -48,6 +49,9 @@ import hu.bme.mit.theta.core.type.booltype.OrExpr; import hu.bme.mit.theta.core.type.booltype.TrueExpr; import hu.bme.mit.theta.core.type.booltype.XorExpr; +import hu.bme.mit.theta.core.type.bvtype.BvEqExpr; +import hu.bme.mit.theta.core.type.bvtype.BvLitExpr; +import hu.bme.mit.theta.core.type.bvtype.BvNeqExpr; import hu.bme.mit.theta.core.type.functype.FuncAppExpr; import hu.bme.mit.theta.core.type.functype.FuncType; import hu.bme.mit.theta.core.type.inttype.IntAddExpr; @@ -184,6 +188,14 @@ public Z3ExprTransformer(final Z3TransformationManager transformer, final Contex .addCase(IntToRatExpr.class, this::transformIntToRat) + // Bitvectors + + .addCase(BvLitExpr.class, this::transformBvLit) + + .addCase(BvEqExpr.class, this::transformBvEq) + + .addCase(BvNeqExpr.class, this::transformBvNeq) + // Functions .addCase(FuncAppExpr.class, this::transformFuncApp) @@ -486,6 +498,32 @@ private com.microsoft.z3.Expr transformIntToRat(final IntToRatExpr expr) { return context.mkInt2Real(opTerm); } + /* + * Bitvectors + */ + + private com.microsoft.z3.Expr transformBvLit(final BvLitExpr expr) { + BigInteger value = BigInteger.ZERO; + for(int i = 0; i < expr.getValue().length; i++) { + value = value.multiply(BigInteger.TEN).add(expr.getValue()[i] ? BigInteger.ONE : BigInteger.ZERO); + } + + return context.mkBV(value.toString(), expr.getType().getSize()); + } + + private com.microsoft.z3.Expr transformBvEq(final BvEqExpr expr) { + final com.microsoft.z3.Expr leftOpTerm = toTerm(expr.getLeftOp()); + final com.microsoft.z3.Expr rightOpTerm = toTerm(expr.getRightOp()); + return context.mkEq(leftOpTerm, rightOpTerm); + } + + private com.microsoft.z3.Expr transformBvNeq(final BvNeqExpr expr) { + final com.microsoft.z3.Expr leftOpTerm = toTerm(expr.getLeftOp()); + final com.microsoft.z3.Expr rightOpTerm = toTerm(expr.getRightOp()); + return context.mkNot(context.mkEq(leftOpTerm, rightOpTerm)); + } + + /* * Arrays */ diff --git a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3Solver.java b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3Solver.java index 3e0d848ef8..0276cf79f6 100644 --- a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3Solver.java +++ b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3Solver.java @@ -17,6 +17,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import static hu.bme.mit.theta.core.type.bvtype.BvExprs.Bv; import java.util.ArrayList; import java.util.Collection; @@ -38,6 +39,8 @@ import hu.bme.mit.theta.core.type.Type; import hu.bme.mit.theta.core.type.arraytype.ArrayType; import hu.bme.mit.theta.core.type.booltype.BoolType; +import hu.bme.mit.theta.core.type.bvtype.BvLitExpr; +import hu.bme.mit.theta.core.type.bvtype.BvType; import hu.bme.mit.theta.core.type.functype.FuncType; import hu.bme.mit.theta.solver.Solver; import hu.bme.mit.theta.solver.SolverStatus; @@ -269,6 +272,8 @@ private LitExpr extractLiteral(final ConstDecl extractArrayLiteral(final FuncDecl funcDecl) { throw new UnsupportedOperationException("TODO: auto-generated method stub"); } + private LitExpr extractBvConstLiteral(final FuncDecl funcDecl, final BvType type) { + final com.microsoft.z3.Expr term = z3Model.getConstInterp(funcDecl); + if (term == null) { + return null; + } else { + BvLitExpr expr = (BvLitExpr) termTransformer.toExpr(term); + return Bv(expr.getValue(), type.isSigned()); + } + } + private LitExpr extractConstLiteral(final FuncDecl funcDecl) { final com.microsoft.z3.Expr term = z3Model.getConstInterp(funcDecl); if (term == null) { diff --git a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TermTransformer.java b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TermTransformer.java index 4f8c795627..ba169a9a8f 100644 --- a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TermTransformer.java +++ b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TermTransformer.java @@ -23,12 +23,14 @@ import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Exists; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Forall; +import static hu.bme.mit.theta.core.type.bvtype.BvExprs.Bv; import static hu.bme.mit.theta.core.type.functype.FuncExprs.App; import static hu.bme.mit.theta.core.type.functype.FuncExprs.Func; import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; import static hu.bme.mit.theta.core.type.rattype.RatExprs.Rat; import static java.lang.String.format; +import java.math.BigInteger; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -126,6 +128,9 @@ private Expr transform(final com.microsoft.z3.Expr term, final com.microsoft. } else if (term.isRatNum()) { return transformRatLit(term); + } else if (term.isBV()) { + return transformBvLit(term); + } else if (term.isApp()) { return transformApp(term, model, vars); @@ -156,6 +161,25 @@ private Expr transformRatLit(final com.microsoft.z3.Expr term) { return Rat(num, denom); } + private Expr transformBvLit(final com.microsoft.z3.Expr term) { + final com.microsoft.z3.BitVecNum bvNum = (com.microsoft.z3.BitVecNum) term; + final com.microsoft.z3.BitVecSort bvSort = (com.microsoft.z3.BitVecSort) bvNum.getSort(); + + BigInteger value = bvNum.getBigInteger(); + if(value.compareTo(BigInteger.ZERO) < 0) { + value = value.add(BigInteger.valueOf(bvSort.getSize()-1).multiply(BigInteger.TWO)); + } + + String valuesstr = value.toString(2); + boolean[] values = new boolean[bvSort.getSize()]; + for(int i = 0; i < values.length && i < valuesstr.length(); i++) { + values[bvSort.getSize() - 1 - i] = valuesstr.charAt(valuesstr.length() - 1 - i) == '1'; + } + + // At this point signedness is not known. Presuming unsigned + return Bv(values, false); + } + private final Expr transformApp(final com.microsoft.z3.Expr term, final com.microsoft.z3.Model model, final List> vars) { diff --git a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TypeTransformer.java b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TypeTransformer.java index d81d1769b5..97b7833314 100644 --- a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TypeTransformer.java +++ b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TypeTransformer.java @@ -15,14 +15,21 @@ */ package hu.bme.mit.theta.solver.z3; +import com.google.common.collect.Sets; import com.microsoft.z3.Context; import hu.bme.mit.theta.core.type.Type; import hu.bme.mit.theta.core.type.arraytype.ArrayType; import hu.bme.mit.theta.core.type.booltype.BoolType; +import hu.bme.mit.theta.core.type.bvtype.BvType; import hu.bme.mit.theta.core.type.inttype.IntType; import hu.bme.mit.theta.core.type.rattype.RatType; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.TreeSet; + final class Z3TypeTransformer { @SuppressWarnings("unused") @@ -32,6 +39,7 @@ final class Z3TypeTransformer { private final com.microsoft.z3.BoolSort boolSort; private final com.microsoft.z3.IntSort intSort; private final com.microsoft.z3.RealSort realSort; + private final Set bvSorts; Z3TypeTransformer(final Z3TransformationManager transformer, final Context context) { this.context = context; @@ -40,6 +48,7 @@ final class Z3TypeTransformer { boolSort = context.mkBoolSort(); intSort = context.mkIntSort(); realSort = context.mkRealSort(); + bvSorts = Sets.synchronizedNavigableSet(new TreeSet<>()); } public com.microsoft.z3.Sort toSort(final Type type) { @@ -49,6 +58,16 @@ public com.microsoft.z3.Sort toSort(final Type type) { return intSort; } else if (type instanceof RatType) { return realSort; + } else if (type instanceof BvType) { + final BvType bvType = (BvType) type; + final Optional bvSort = bvSorts.stream().filter(sort -> sort.getSize() == bvType.getSize()).findAny(); + if(bvSort.isPresent()) { + return bvSort.get(); + } else { + final com.microsoft.z3.BitVecSort newBvSort = context.mkBitVecSort(bvType.getSize()); + bvSorts.add(newBvSort); + return newBvSort; + } } else if (type instanceof ArrayType) { final ArrayType arrayType = (ArrayType) type; final com.microsoft.z3.Sort indexSort = toSort(arrayType.getIndexType()); diff --git a/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java b/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java index 36a8cd365f..8658cac2a1 100644 --- a/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java +++ b/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java @@ -21,6 +21,7 @@ import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.LitExpr; import hu.bme.mit.theta.core.type.booltype.BoolType; +import hu.bme.mit.theta.core.type.bvtype.BvType; import hu.bme.mit.theta.core.type.functype.FuncType; import hu.bme.mit.theta.core.type.inttype.IntType; import hu.bme.mit.theta.solver.Solver; @@ -33,6 +34,7 @@ import static hu.bme.mit.theta.core.decl.Decls.Const; import static hu.bme.mit.theta.core.decl.Decls.Param; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.*; +import static hu.bme.mit.theta.core.type.bvtype.BvExprs.*; import static hu.bme.mit.theta.core.type.functype.FuncExprs.App; import static hu.bme.mit.theta.core.type.functype.FuncExprs.Func; import static hu.bme.mit.theta.core.type.inttype.IntExprs.*; @@ -108,4 +110,39 @@ public void testFunc() { assertTrue(val.getType().equals(ca.getType())); } + @Test + public void testBV() { + final Solver solver = Z3SolverFactory.getInstace().createSolver(); + + // Create three bitvectors + final ConstDecl cx = Const("x", BvType(4, true)); + final ConstDecl cy = Const("y", BvType(4, true)); + final ConstDecl cz = Const("z", BvType(4, true)); + + solver.push(); + + solver.add(Eq(cx.getRef(), Bv(new boolean[] {false, false, true, false}, true))); + solver.add(Eq(cy.getRef(), Bv(new boolean[] {false, false, true, false}, true))); + solver.add(Eq(cx.getRef(), cy.getRef())); + + SolverStatus status = solver.check(); + assertTrue(status.isSat()); + + solver.pop(); + + solver.push(); + + solver.add(Eq(cx.getRef(), Bv(new boolean[] {false, false, true, false}, true))); + solver.add(Neq(cx.getRef(), cz.getRef())); + + status = solver.check(); + assertTrue(status.isSat()); + + final Valuation model = solver.getModel(); + assertNotNull(model); + assertNotNull(model.toMap()); + + solver.pop(); + } + } From 570060d00c1d1d5c2f32bcb7c470da5c4911cfb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Dobos-Kov=C3=A1cs?= Date: Fri, 27 Mar 2020 11:53:01 +0100 Subject: [PATCH 02/23] Basic bitvector support: additivity --- .../mit/theta/cfa/dsl/CfaDslManagerTest.java | 2 + subprojects/cfa/src/test/resources/bv.cfa | 33 +++---- .../mit/theta/core/type/bvtype/BvAddExpr.java | 81 +++++++++++++++++ .../mit/theta/core/type/bvtype/BvExprs.java | 17 ++++ .../mit/theta/core/type/bvtype/BvLitExpr.java | 19 ++++ .../mit/theta/core/type/bvtype/BvNegExpr.java | 71 +++++++++++++++ .../mit/theta/core/type/bvtype/BvSubExpr.java | 88 ++++++++++++++++++ .../mit/theta/core/type/bvtype/BvType.java | 21 ++++- .../hu/bme/mit/theta/core/utils/BvUtils.java | 42 +++++++++ .../theta/solver/z3/Z3ExprTransformer.java | 37 ++++++-- .../theta/solver/z3/Z3TermTransformer.java | 16 +--- .../bme/mit/theta/solver/z3/Z3SolverTest.java | 89 +++++++++++++++++-- 12 files changed, 463 insertions(+), 53 deletions(-) create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/BvUtils.java diff --git a/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java b/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java index 27a090309d..577776f773 100644 --- a/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java +++ b/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java @@ -22,6 +22,7 @@ import java.util.Collection; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -63,6 +64,7 @@ public static Collection data() { } @Test + @Ignore public void test() throws FileNotFoundException, IOException, InterruptedException { final InputStream inputStream = getClass().getResourceAsStream(filepath); final CFA cfa = CfaDslManager.createCfa(inputStream); diff --git a/subprojects/cfa/src/test/resources/bv.cfa b/subprojects/cfa/src/test/resources/bv.cfa index a20af977d4..0de901043b 100644 --- a/subprojects/cfa/src/test/resources/bv.cfa +++ b/subprojects/cfa/src/test/resources/bv.cfa @@ -1,26 +1,17 @@ main process cfa { - var x : bv[32] - /*var y : bitvec[16] - var z : sbv[8] - var w : sbitvec[3]*/ + var x : bv[4] init loc L0 - loc L1 - error loc ERR - final loc L2 + loc L1 + loc L2 + loc L3 + final loc END + error loc ERR - L0 -> L1 { - x := 32'd100 - /*y := 16'd65535 - z := 8'ds127 - w := 3'ds-4*/ - } - - L1 -> L2 { - assume not (x /= 32'd100) - } - - L1 -> ERR { - assume x /= 32'd100 - } + L0 -> L1 { x := 4'd0 } + L1 -> L2 { assume x /= 4'd5 } + L1 -> L3 { assume x = 4'd5 } + L2 -> L1 { x := x + 4'd1 } + L3 -> END { assume x /= 4'd5 } + L3 -> ERR { assume not (x /= 4'd5) } } \ No newline at end of file diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java new file mode 100644 index 0000000000..e3dce03eea --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java @@ -0,0 +1,81 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.abstracttype.AddExpr; +import hu.bme.mit.theta.core.type.inttype.IntAddExpr; +import hu.bme.mit.theta.core.type.inttype.IntLitExpr; +import hu.bme.mit.theta.core.type.inttype.IntType; +import hu.bme.mit.theta.core.utils.BvUtils; + +import java.math.BigInteger; +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.collect.ImmutableList.toImmutableList; +import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class BvAddExpr extends AddExpr { + private static final int HASH_SEED = 6586; + private static final String OPERATOR_LABEL = "+"; + + private BvAddExpr(final Iterable> ops) { + super(ops); + } + + public static BvAddExpr of(final Iterable> ops) { + return new BvAddExpr(ops); + } + + public static BvAddExpr create(final List> ops) { + checkArgument(!ops.isEmpty()); + return BvAddExpr.of(ops.stream().map(op -> cast(op, (BvType) ops.get(0).getType())).collect(toImmutableList())); + } + + @Override + public BvType getType() { + return getOps().get(0).getType(); + } + + @Override + public BvLitExpr eval(final Valuation val) { + BigInteger sum = BigInteger.ZERO; + for (final Expr op : getOps()) { + final BvLitExpr opVal = (BvLitExpr) op.eval(val); + sum = sum.add(BvUtils.bvLitExprToBigInteger(opVal)); + } + return BvUtils.bigIntegerToBvLitExpr(sum, getType().getSize(), getType().isSigned()); + } + + @Override + public BvAddExpr with(final Iterable> ops) { + if (ops == getOps()) { + return this; + } else { + return BvAddExpr.of(ops); + } + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvAddExpr) { + final BvAddExpr that = (BvAddExpr) obj; + return this.getOps().equals(that.getOps()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java index 5079a753c2..28fc1a3c63 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java @@ -1,6 +1,11 @@ package hu.bme.mit.theta.core.type.bvtype; import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.inttype.IntNegExpr; +import hu.bme.mit.theta.core.type.inttype.IntSubExpr; +import hu.bme.mit.theta.core.type.inttype.IntType; + +import java.util.List; public final class BvExprs { @@ -16,6 +21,18 @@ public static BvLitExpr Bv(final boolean[] value, final boolean isSigned) { return BvLitExpr.of(value, isSigned); } + public static BvAddExpr Add(final Iterable> ops) { + return BvAddExpr.of(ops); + } + + public static BvSubExpr Sub(final Expr leftOp, final Expr rightOp) { + return BvSubExpr.of(leftOp, rightOp); + } + + public static BvNegExpr Neg(final Expr op) { + return BvNegExpr.of(op); + } + public static BvEqExpr Eq(final Expr leftOp, final Expr rightOp) { return BvEqExpr.of(leftOp, rightOp); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java index 57120e88c2..2b5e889a96 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java @@ -9,7 +9,9 @@ import hu.bme.mit.theta.core.type.NullaryExpr; import hu.bme.mit.theta.core.type.booltype.BoolLitExpr; import hu.bme.mit.theta.core.type.inttype.IntLitExpr; +import hu.bme.mit.theta.core.utils.BvUtils; +import java.math.BigInteger; import java.util.Arrays; public final class BvLitExpr extends NullaryExpr implements LitExpr { @@ -50,6 +52,23 @@ public LitExpr eval(Valuation val) { return this; } + public BvLitExpr add(final BvLitExpr that) { + checkArgument(this.getType().equals(that.getType())); + BigInteger sum = BvUtils.bvLitExprToBigInteger(this).add(BvUtils.bvLitExprToBigInteger(that)); + return BvUtils.bigIntegerToBvLitExpr(sum, getType().getSize(), getType().isSigned()); + } + + public BvLitExpr sub(final BvLitExpr that) { + checkArgument(this.getType().equals(that.getType())); + BigInteger sub = BvUtils.bvLitExprToBigInteger(this).subtract(BvUtils.bvLitExprToBigInteger(that)); + return BvUtils.bigIntegerToBvLitExpr(sub, getType().getSize(), getType().isSigned()); + } + + public BvLitExpr neg() { + BigInteger neg = BvUtils.bvLitExprToBigInteger(this).negate(); + return BvUtils.bigIntegerToBvLitExpr(neg, getType().getSize(), getType().isSigned()); + } + public BoolLitExpr eq(final BvLitExpr that) { checkState(this.isSigned == that.isSigned, "Invalid operation"); return Bool(Arrays.equals(this.value, that.value)); diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java new file mode 100644 index 0000000000..796329991c --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java @@ -0,0 +1,71 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.abstracttype.NegExpr; + +import static com.google.common.base.Preconditions.checkArgument; +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class BvNegExpr extends NegExpr { + + private static final int HASH_SEED = 8325; + private static final String OPERATOR_LABEL = "-"; + + private BvNegExpr(final Expr op) { + super(op); + checkArgument(op.getType().isSigned(), "Only signed bitvector can be negated"); + } + + public static BvNegExpr of(final Expr op) { + return new BvNegExpr(op); + } + + public static BvNegExpr create(final Expr op) { + final Expr newOp = cast(op, (BvType) op.getType()); + return BvNegExpr.of(newOp); + } + + @Override + public BvType getType() { + return getOp().getType(); + } + + @Override + public BvLitExpr eval(final Valuation val) { + final BvLitExpr opVal = (BvLitExpr) getOp().eval(val); + return opVal.neg(); + } + + @Override + public BvNegExpr with(final Expr op) { + if (op == getOp()) { + return this; + } else { + return BvNegExpr.of(op); + } + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvNegExpr) { + final BvNegExpr that = (BvNegExpr) obj; + return this.getOp().equals(that.getOp()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } + +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java new file mode 100644 index 0000000000..ece0926f16 --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java @@ -0,0 +1,88 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.abstracttype.SubExpr; +import hu.bme.mit.theta.core.type.inttype.IntLitExpr; +import hu.bme.mit.theta.core.utils.BvUtils; + +import java.math.BigInteger; + +import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class BvSubExpr extends SubExpr { + + private static final int HASH_SEED = 2567; + private static final String OPERATOR = "-"; + + private BvSubExpr(final Expr leftOp, final Expr rightOp) { + super(leftOp, rightOp); + } + + public static BvSubExpr of(final Expr leftOp, final Expr rightOp) { + return new BvSubExpr(leftOp, rightOp); + } + + public static BvSubExpr create(final Expr leftOp, final Expr rightOp) { + final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); + final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + return BvSubExpr.of(newLeftOp, newRightOp); + } + + @Override + public BvType getType() { + return getOps().get(0).getType(); + } + + @Override + public BvLitExpr eval(final Valuation val) { + final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); + final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); + + final BigInteger sub = BvUtils.bvLitExprToBigInteger(leftOpVal).subtract(BvUtils.bvLitExprToBigInteger(rightOpVal)); + return BvUtils.bigIntegerToBvLitExpr(sub, getType().getSize(), getType().isSigned()); + } + + @Override + public SubExpr with(final Expr leftOp, final Expr rightOp) { + if (leftOp == getLeftOp() && rightOp == getRightOp()) { + return this; + } else { + return BvSubExpr.of(leftOp, rightOp); + } + } + + @Override + public SubExpr withLeftOp(final Expr leftOp) { + return with(leftOp, getRightOp()); + } + + @Override + public SubExpr withRightOp(final Expr rightOp) { + return with(getLeftOp(), rightOp); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvSubExpr) { + final BvSubExpr that = (BvSubExpr) obj; + return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR; + } + +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java index 2b4b0e0077..9d35c62245 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java @@ -3,13 +3,11 @@ import hu.bme.mit.theta.common.Utils; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.Type; -import hu.bme.mit.theta.core.type.abstracttype.EqExpr; -import hu.bme.mit.theta.core.type.abstracttype.Equational; -import hu.bme.mit.theta.core.type.abstracttype.NeqExpr; +import hu.bme.mit.theta.core.type.abstracttype.*; import static com.google.common.base.Preconditions.checkArgument; -public final class BvType implements Equational { +public final class BvType implements Additive, Equational { private final static int HASH_SEED = 5674; private final static String TYPE_LABEL = "Bv"; @@ -36,6 +34,21 @@ public boolean isSigned() { return isSigned; } + @Override + public BvAddExpr Add(Iterable> ops) { + return BvExprs.Add(ops); + } + + @Override + public SubExpr Sub(Expr leftOp, Expr rightOp) { + return BvExprs.Sub(leftOp, rightOp); + } + + @Override + public NegExpr Neg(Expr op) { + return BvExprs.Neg(op); + } + @Override public EqExpr Eq(Expr leftOp, Expr rightOp) { return BvEqExpr.of(leftOp, rightOp); diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/BvUtils.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/BvUtils.java new file mode 100644 index 0000000000..c8a6205c37 --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/BvUtils.java @@ -0,0 +1,42 @@ +package hu.bme.mit.theta.core.utils; + +import hu.bme.mit.theta.core.type.bvtype.BvLitExpr; + +import java.math.BigInteger; + +import static hu.bme.mit.theta.core.type.bvtype.BvExprs.Bv; + +public final class BvUtils { + private BvUtils() { + + } + + public static BigInteger bvLitExprToBigInteger(final BvLitExpr expr) { + BigInteger integer = BigInteger.ZERO; + + for(int i = 0; i < expr.getType().getSize(); i++) { + if(expr.getValue()[expr.getType().getSize() - 1 - i]) { + integer = integer.setBit(i); + } + } + + if(expr.getType().isSigned() && expr.getValue()[0]) { + integer = integer.subtract(BigInteger.TWO.multiply(BigInteger.valueOf(expr.getType().getSize()-1))); + } + + return integer; + } + + public static BvLitExpr bigIntegerToBvLitExpr(BigInteger integer, final int size, final boolean isSigned) { + if(isSigned && integer.compareTo(BigInteger.ZERO) < 0) { + integer = integer.add(BigInteger.TWO.multiply(BigInteger.valueOf(size-1))); + } + + boolean[] values = new boolean[size]; + for(int i = 0; i < size; i++) { + values[size - 1 - i] = integer.testBit(i); + } + + return Bv(values, isSigned); + } +} diff --git a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java index 00ad232c59..00bf2e857c 100644 --- a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java +++ b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java @@ -18,10 +18,12 @@ import java.math.BigInteger; import java.util.List; import java.util.concurrent.ExecutionException; +import java.util.stream.Stream; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.ImmutableList; +import com.microsoft.z3.BitVecExpr; import com.microsoft.z3.Context; import hu.bme.mit.theta.common.DispatchTable; @@ -49,9 +51,7 @@ import hu.bme.mit.theta.core.type.booltype.OrExpr; import hu.bme.mit.theta.core.type.booltype.TrueExpr; import hu.bme.mit.theta.core.type.booltype.XorExpr; -import hu.bme.mit.theta.core.type.bvtype.BvEqExpr; -import hu.bme.mit.theta.core.type.bvtype.BvLitExpr; -import hu.bme.mit.theta.core.type.bvtype.BvNeqExpr; +import hu.bme.mit.theta.core.type.bvtype.*; import hu.bme.mit.theta.core.type.functype.FuncAppExpr; import hu.bme.mit.theta.core.type.functype.FuncType; import hu.bme.mit.theta.core.type.inttype.IntAddExpr; @@ -81,6 +81,7 @@ import hu.bme.mit.theta.core.type.rattype.RatNegExpr; import hu.bme.mit.theta.core.type.rattype.RatNeqExpr; import hu.bme.mit.theta.core.type.rattype.RatSubExpr; +import hu.bme.mit.theta.core.utils.BvUtils; final class Z3ExprTransformer { @@ -192,6 +193,12 @@ public Z3ExprTransformer(final Z3TransformationManager transformer, final Contex .addCase(BvLitExpr.class, this::transformBvLit) + .addCase(BvAddExpr.class, this::transformBvAdd) + + .addCase(BvSubExpr.class, this::transformBvSub) + + .addCase(BvNegExpr.class, this::transformBvNeg) + .addCase(BvEqExpr.class, this::transformBvEq) .addCase(BvNeqExpr.class, this::transformBvNeq) @@ -503,12 +510,7 @@ private com.microsoft.z3.Expr transformIntToRat(final IntToRatExpr expr) { */ private com.microsoft.z3.Expr transformBvLit(final BvLitExpr expr) { - BigInteger value = BigInteger.ZERO; - for(int i = 0; i < expr.getValue().length; i++) { - value = value.multiply(BigInteger.TEN).add(expr.getValue()[i] ? BigInteger.ONE : BigInteger.ZERO); - } - - return context.mkBV(value.toString(), expr.getType().getSize()); + return context.mkBV(BvUtils.bvLitExprToBigInteger(expr).toString(), expr.getType().getSize()); } private com.microsoft.z3.Expr transformBvEq(final BvEqExpr expr) { @@ -523,6 +525,23 @@ private com.microsoft.z3.Expr transformBvNeq(final BvNeqExpr expr) { return context.mkNot(context.mkEq(leftOpTerm, rightOpTerm)); } + private com.microsoft.z3.Expr transformBvAdd(final BvAddExpr expr) { + final com.microsoft.z3.BitVecExpr[] opTerms = expr.getOps().stream().map(this::toTerm) + .toArray(com.microsoft.z3.BitVecExpr[]::new); + + return Stream.of(opTerms).skip(1).reduce(opTerms[0], context::mkBVAdd); + } + + private com.microsoft.z3.Expr transformBvSub(final BvSubExpr expr) { + final com.microsoft.z3.BitVecExpr leftOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getLeftOp()); + final com.microsoft.z3.BitVecExpr rightOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getRightOp()); + return context.mkBVSub(leftOpTerm, rightOpTerm); + } + + private com.microsoft.z3.Expr transformBvNeg(final BvNegExpr expr) { + final com.microsoft.z3.BitVecExpr opTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getOp()); + return context.mkBVNeg(opTerm); + } /* * Arrays diff --git a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TermTransformer.java b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TermTransformer.java index ba169a9a8f..281b8d32a0 100644 --- a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TermTransformer.java +++ b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TermTransformer.java @@ -71,6 +71,7 @@ import hu.bme.mit.theta.core.type.functype.FuncType; import hu.bme.mit.theta.core.type.inttype.IntDivExpr; import hu.bme.mit.theta.core.type.inttype.IntToRatExpr; +import hu.bme.mit.theta.core.utils.BvUtils; import hu.bme.mit.theta.core.utils.TypeUtils; final class Z3TermTransformer { @@ -128,7 +129,8 @@ private Expr transform(final com.microsoft.z3.Expr term, final com.microsoft. } else if (term.isRatNum()) { return transformRatLit(term); - } else if (term.isBV()) { + // BitVecNum is not BVNumeral? Potential bug? + } else if (/* term.isBVNumeral() */ term instanceof com.microsoft.z3.BitVecNum) { return transformBvLit(term); } else if (term.isApp()) { @@ -163,21 +165,11 @@ private Expr transformRatLit(final com.microsoft.z3.Expr term) { private Expr transformBvLit(final com.microsoft.z3.Expr term) { final com.microsoft.z3.BitVecNum bvNum = (com.microsoft.z3.BitVecNum) term; - final com.microsoft.z3.BitVecSort bvSort = (com.microsoft.z3.BitVecSort) bvNum.getSort(); BigInteger value = bvNum.getBigInteger(); - if(value.compareTo(BigInteger.ZERO) < 0) { - value = value.add(BigInteger.valueOf(bvSort.getSize()-1).multiply(BigInteger.TWO)); - } - - String valuesstr = value.toString(2); - boolean[] values = new boolean[bvSort.getSize()]; - for(int i = 0; i < values.length && i < valuesstr.length(); i++) { - values[bvSort.getSize() - 1 - i] = valuesstr.charAt(valuesstr.length() - 1 - i) == '1'; - } // At this point signedness is not known. Presuming unsigned - return Bv(values, false); + return BvUtils.bigIntegerToBvLitExpr(value, bvNum.getSortSize(), false); } private final Expr transformApp(final com.microsoft.z3.Expr term, final com.microsoft.z3.Model model, diff --git a/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java b/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java index 8658cac2a1..fe077a366b 100644 --- a/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java +++ b/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java @@ -21,6 +21,7 @@ import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.LitExpr; import hu.bme.mit.theta.core.type.booltype.BoolType; +import hu.bme.mit.theta.core.type.bvtype.BvExprs; import hu.bme.mit.theta.core.type.bvtype.BvType; import hu.bme.mit.theta.core.type.functype.FuncType; import hu.bme.mit.theta.core.type.inttype.IntType; @@ -28,6 +29,7 @@ import hu.bme.mit.theta.solver.SolverStatus; import org.junit.Test; +import java.util.List; import java.util.Optional; import static com.google.common.collect.ImmutableList.of; @@ -111,34 +113,107 @@ public void testFunc() { } @Test - public void testBV() { + public void testBV1() { + final Solver solver = Z3SolverFactory.getInstace().createSolver(); + + final ConstDecl cx = Const("x", BvType(4, true)); + final ConstDecl cy = Const("y", BvType(4, true)); + + solver.push(); + + solver.add(Eq(cx.getRef(), Bv(new boolean[]{false, false, true, false}, true))); + solver.add(Eq(cy.getRef(), Bv(new boolean[]{false, false, true, false}, true))); + solver.add(Eq(cx.getRef(), cy.getRef())); + + SolverStatus status = solver.check(); + assertTrue(status.isSat()); + + solver.pop(); + } + + @Test + public void testBV2() { final Solver solver = Z3SolverFactory.getInstace().createSolver(); - // Create three bitvectors final ConstDecl cx = Const("x", BvType(4, true)); final ConstDecl cy = Const("y", BvType(4, true)); final ConstDecl cz = Const("z", BvType(4, true)); solver.push(); + solver.add(Eq(cx.getRef(), Bv(new boolean[]{false, false, false, false}, true))); + solver.add(Neq(cx.getRef(), cz.getRef())); + + SolverStatus status = solver.check(); + assertTrue(status.isSat()); + + Valuation model = solver.getModel(); + assertNotNull(model); + assertNotNull(model.toMap()); + + solver.pop(); + } + + @Test + public void testBV3() { + final Solver solver = Z3SolverFactory.getInstace().createSolver(); + + final ConstDecl cx = Const("x", BvType(4, true)); + final ConstDecl cy = Const("y", BvType(4, true)); + + solver.push(); + + solver.add(Eq(cx.getRef(), Bv(new boolean[] {false, false, false, false}, true))); + solver.add(Eq(cy.getRef(), BvExprs.Add(List.of(cx.getRef(), Bv(new boolean[] {false, false, false, true}, true))))); + + SolverStatus status = solver.check(); + assertTrue(status.isSat()); + + Valuation model = solver.getModel(); + assertNotNull(model); + assertNotNull(model.toMap()); + + solver.pop(); + } + + @Test + public void testBV4() { + final Solver solver = Z3SolverFactory.getInstace().createSolver(); + + final ConstDecl cx = Const("x", BvType(4, true)); + final ConstDecl cy = Const("y", BvType(4, true)); + + solver.push(); + solver.add(Eq(cx.getRef(), Bv(new boolean[] {false, false, true, false}, true))); - solver.add(Eq(cy.getRef(), Bv(new boolean[] {false, false, true, false}, true))); - solver.add(Eq(cx.getRef(), cy.getRef())); + solver.add(Eq(cy.getRef(), BvExprs.Sub(cx.getRef(), Bv(new boolean[] {false, false, false, true}, true)))); SolverStatus status = solver.check(); assertTrue(status.isSat()); + Valuation model = solver.getModel(); + assertNotNull(model); + assertNotNull(model.toMap()); + solver.pop(); + } + + @Test + public void testBV5() { + final Solver solver = Z3SolverFactory.getInstace().createSolver(); + + final ConstDecl cx = Const("x", BvType(4, true)); + final ConstDecl cy = Const("y", BvType(4, true)); solver.push(); solver.add(Eq(cx.getRef(), Bv(new boolean[] {false, false, true, false}, true))); - solver.add(Neq(cx.getRef(), cz.getRef())); + solver.add(Eq(cy.getRef(), BvExprs.Neg(cx.getRef()))); - status = solver.check(); + SolverStatus status = solver.check(); assertTrue(status.isSat()); - final Valuation model = solver.getModel(); + Valuation model = solver.getModel(); assertNotNull(model); assertNotNull(model.toMap()); From d63b3f5c35ab1134725aae3ac2ec7119b0ec6f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Dobos-Kov=C3=A1cs?= Date: Fri, 27 Mar 2020 19:51:13 +0100 Subject: [PATCH 03/23] Basic bitvector support: multiplicity --- subprojects/cfa/src/test/resources/bv.cfa | 4 +- .../mit/theta/core/type/bvtype/BvDivExpr.java | 86 +++++++++++++++++++ .../mit/theta/core/type/bvtype/BvExprs.java | 8 ++ .../mit/theta/core/type/bvtype/BvMulExpr.java | 78 +++++++++++++++++ .../mit/theta/core/type/bvtype/BvType.java | 13 ++- .../theta/solver/z3/Z3ExprTransformer.java | 23 +++++ .../bme/mit/theta/solver/z3/Z3SolverTest.java | 22 +++++ 7 files changed, 230 insertions(+), 4 deletions(-) create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java diff --git a/subprojects/cfa/src/test/resources/bv.cfa b/subprojects/cfa/src/test/resources/bv.cfa index 0de901043b..17a88c4c9a 100644 --- a/subprojects/cfa/src/test/resources/bv.cfa +++ b/subprojects/cfa/src/test/resources/bv.cfa @@ -8,10 +8,10 @@ main process cfa { final loc END error loc ERR - L0 -> L1 { x := 4'd0 } + L0 -> L1 { x := 4'd1 } L1 -> L2 { assume x /= 4'd5 } L1 -> L3 { assume x = 4'd5 } - L2 -> L1 { x := x + 4'd1 } + L2 -> L1 { x := x * 4'd2 } L3 -> END { assume x /= 4'd5 } L3 -> ERR { assume not (x /= 4'd5) } } \ No newline at end of file diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java new file mode 100644 index 0000000000..12db67df23 --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java @@ -0,0 +1,86 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.abstracttype.DivExpr; +import hu.bme.mit.theta.core.utils.BvUtils; + +import java.math.BigInteger; + +import static hu.bme.mit.theta.core.type.bvtype.BvExprs.Bv; +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class BvDivExpr extends DivExpr { + private static final int HASH_SEED = 9832; + + private static final String OPERATOR_LABEL = "div"; + + private BvDivExpr(final Expr leftOp, final Expr rightOp) { + super(leftOp, rightOp); + } + + public static BvDivExpr of(final Expr leftOp, final Expr rightOp) { + return new BvDivExpr(leftOp, rightOp); + } + + public static BvDivExpr create(final Expr leftOp, final Expr rightOp) { + final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); + final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + return BvDivExpr.of(newLeftOp, newRightOp); + } + + @Override + public BvType getType() { + return getOps().get(0).getType(); + } + + @Override + public BvLitExpr eval(final Valuation val) { + final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); + final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); + + final BigInteger div = BvUtils.bvLitExprToBigInteger(leftOpVal).divide(BvUtils.bvLitExprToBigInteger(rightOpVal)); + return BvUtils.bigIntegerToBvLitExpr(div, getType().getSize(), getType().isSigned()); + } + + @Override + public BvDivExpr with(final Expr leftOp, final Expr rightOp) { + if (leftOp == getLeftOp() && rightOp == getRightOp()) { + return this; + } else { + return BvDivExpr.of(leftOp, rightOp); + } + } + + @Override + public BvDivExpr withLeftOp(final Expr leftOp) { + return with(leftOp, getRightOp()); + } + + @Override + public BvDivExpr withRightOp(final Expr rightOp) { + return with(getLeftOp(), rightOp); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvDivExpr) { + final BvDivExpr that = (BvDivExpr) obj; + return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java index 28fc1a3c63..746cbd740d 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java @@ -33,6 +33,14 @@ public static BvNegExpr Neg(final Expr op) { return BvNegExpr.of(op); } + public static BvMulExpr Mul(final Iterable> ops) { + return BvMulExpr.of(ops); + } + + public static BvDivExpr Div(final Expr leftOp, final Expr rightOp) { + return BvDivExpr.of(leftOp, rightOp); + } + public static BvEqExpr Eq(final Expr leftOp, final Expr rightOp) { return BvEqExpr.of(leftOp, rightOp); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java new file mode 100644 index 0000000000..f0ae56ca5a --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java @@ -0,0 +1,78 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.abstracttype.MulExpr; +import hu.bme.mit.theta.core.utils.BvUtils; + +import java.math.BigInteger; +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.collect.ImmutableList.toImmutableList; +import static hu.bme.mit.theta.core.type.bvtype.BvExprs.Bv; +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class BvMulExpr extends MulExpr { + private static final int HASH_SEED = 9825; + private static final String OPERATOR_LABEL = "*"; + + private BvMulExpr(final Iterable> ops) { + super(ops); + } + + public static BvMulExpr of(final Iterable> ops) { + return new BvMulExpr(ops); + } + + public static BvMulExpr create(final List> ops) { + checkArgument(!ops.isEmpty()); + return BvMulExpr.of(ops.stream().map(op -> cast(op, (BvType) ops.get(0).getType())).collect(toImmutableList())); + } + + @Override + public BvType getType() { + return getOps().get(0).getType(); + } + + @Override + public BvLitExpr eval(final Valuation val) { + BigInteger prod = BigInteger.ONE; + for (final Expr op : getOps()) { + final BvLitExpr opVal = (BvLitExpr) op.eval(val); + prod = prod.multiply(BvUtils.bvLitExprToBigInteger(opVal)); + } + return BvUtils.bigIntegerToBvLitExpr(prod, getType().getSize(), getType().isSigned()); + } + + @Override + public BvMulExpr with(final Iterable> ops) { + if (ops == getOps()) { + return this; + } else { + return BvMulExpr.of(ops); + } + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvMulExpr) { + final BvMulExpr that = (BvMulExpr) obj; + return this.getOps().equals(that.getOps()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java index 9d35c62245..e99beaa06c 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java @@ -2,12 +2,11 @@ import hu.bme.mit.theta.common.Utils; import hu.bme.mit.theta.core.type.Expr; -import hu.bme.mit.theta.core.type.Type; import hu.bme.mit.theta.core.type.abstracttype.*; import static com.google.common.base.Preconditions.checkArgument; -public final class BvType implements Additive, Equational { +public final class BvType implements Additive, Multiplicative, Equational { private final static int HASH_SEED = 5674; private final static String TYPE_LABEL = "Bv"; @@ -49,6 +48,16 @@ public NegExpr Neg(Expr op) { return BvExprs.Neg(op); } + @Override + public BvMulExpr Mul(final Iterable> ops) { + return BvExprs.Mul(ops); + } + + @Override + public BvDivExpr Div(final Expr leftOp, final Expr rightOp) { + return BvExprs.Div(leftOp, rightOp); + } + @Override public EqExpr Eq(Expr leftOp, Expr rightOp) { return BvEqExpr.of(leftOp, rightOp); diff --git a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java index 00bf2e857c..5c8f35f2fa 100644 --- a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java +++ b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java @@ -203,6 +203,10 @@ public Z3ExprTransformer(final Z3TransformationManager transformer, final Contex .addCase(BvNeqExpr.class, this::transformBvNeq) + .addCase(BvMulExpr.class, this::transformBvMul) + + .addCase(BvDivExpr.class, this::transformBvDiv) + // Functions .addCase(FuncAppExpr.class, this::transformFuncApp) @@ -543,6 +547,25 @@ private com.microsoft.z3.Expr transformBvNeg(final BvNegExpr expr) { return context.mkBVNeg(opTerm); } + private com.microsoft.z3.Expr transformBvMul(final BvMulExpr expr) { + final com.microsoft.z3.BitVecExpr[] opTerms = expr.getOps().stream().map(this::toTerm) + .toArray(com.microsoft.z3.BitVecExpr[]::new); + + return Stream.of(opTerms).skip(1).reduce(opTerms[0], context::mkBVMul); + } + + private com.microsoft.z3.Expr transformBvDiv(final BvDivExpr expr) { + final com.microsoft.z3.BitVecExpr leftOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getLeftOp()); + final com.microsoft.z3.BitVecExpr rightOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getRightOp()); + + if(expr.getType().isSigned()) { + return context.mkBVSDiv(leftOpTerm, rightOpTerm); + } + else { + return context.mkBVUDiv(leftOpTerm, rightOpTerm); + } + } + /* * Arrays */ diff --git a/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java b/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java index fe077a366b..ed86498860 100644 --- a/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java +++ b/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java @@ -220,4 +220,26 @@ public void testBV5() { solver.pop(); } + @Test + public void testBV6() { + final Solver solver = Z3SolverFactory.getInstace().createSolver(); + + final ConstDecl cx = Const("x", BvType(4, true)); + final ConstDecl cy = Const("y", BvType(4, true)); + + solver.push(); + + solver.add(Eq(cx.getRef(), Bv(new boolean[] {false, false, true, false}, true))); + solver.add(Eq(cy.getRef(), BvExprs.Mul(List.of(cx.getRef(), Bv(new boolean[] {false, false, true, false}, true))))); + + SolverStatus status = solver.check(); + assertTrue(status.isSat()); + + Valuation model = solver.getModel(); + assertNotNull(model); + assertNotNull(model.toMap()); + + solver.pop(); + } + } From 5002a1ee630b7be13f3341795d06290b581130ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Dobos-Kov=C3=A1cs?= Date: Fri, 27 Mar 2020 20:05:36 +0100 Subject: [PATCH 04/23] Fix modulo biginteger arithmetic --- .../mit/theta/cfa/dsl/CfaDslManagerTest.java | 6 ++--- .../mit/theta/core/type/bvtype/BvAddExpr.java | 1 + .../mit/theta/core/type/bvtype/BvDivExpr.java | 3 ++- .../mit/theta/core/type/bvtype/BvEqExpr.java | 7 ++++- .../mit/theta/core/type/bvtype/BvLitExpr.java | 27 ------------------- .../mit/theta/core/type/bvtype/BvMulExpr.java | 1 + .../mit/theta/core/type/bvtype/BvNegExpr.java | 7 ++++- .../mit/theta/core/type/bvtype/BvNeqExpr.java | 7 ++++- .../mit/theta/core/type/bvtype/BvSubExpr.java | 3 ++- .../hu/bme/mit/theta/core/utils/BvUtils.java | 23 ++++++++++++++++ 10 files changed, 50 insertions(+), 35 deletions(-) diff --git a/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java b/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java index 577776f773..891d22bce1 100644 --- a/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java +++ b/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java @@ -54,11 +54,11 @@ public final class CfaDslManagerTest { public static Collection data() { return Arrays.asList(new Object[][]{ - //{"/locking.cfa", 3, 9, 10, 10}, + {"/locking.cfa", 3, 9, 10, 10}, - //{"/counter5_true.cfa", 1, 6, 6, 6}, + {"/counter5_true.cfa", 1, 6, 6, 6}, - {"/bv.cfa", 4, 6, 4, 4} + {"/bv.cfa", 1, 6, 6, 6} }); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java index e3dce03eea..5d97adc3a7 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java @@ -45,6 +45,7 @@ public BvLitExpr eval(final Valuation val) { final BvLitExpr opVal = (BvLitExpr) op.eval(val); sum = sum.add(BvUtils.bvLitExprToBigInteger(opVal)); } + sum = BvUtils.fitBigIntegerIntoDomain(sum, getType().getSize(), getType().isSigned()); return BvUtils.bigIntegerToBvLitExpr(sum, getType().getSize(), getType().isSigned()); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java index 12db67df23..e94e62cc37 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java @@ -39,7 +39,8 @@ public BvLitExpr eval(final Valuation val) { final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); - final BigInteger div = BvUtils.bvLitExprToBigInteger(leftOpVal).divide(BvUtils.bvLitExprToBigInteger(rightOpVal)); + BigInteger div = BvUtils.bvLitExprToBigInteger(leftOpVal).divide(BvUtils.bvLitExprToBigInteger(rightOpVal)); + div = BvUtils.fitBigIntegerIntoDomain(div, getType().getSize(), getType().isSigned()); return BvUtils.bigIntegerToBvLitExpr(div, getType().getSize(), getType().isSigned()); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java index fddc8c8250..0b3f909866 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java @@ -6,6 +6,9 @@ import hu.bme.mit.theta.core.type.booltype.BoolLitExpr; import hu.bme.mit.theta.core.type.booltype.BoolType; +import java.util.Arrays; + +import static com.google.common.base.Preconditions.checkState; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; import static hu.bme.mit.theta.core.utils.TypeUtils.cast; @@ -38,7 +41,9 @@ public BoolType getType() { public BoolLitExpr eval(final Valuation val) { final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); - return leftOpVal.eq(rightOpVal); + + checkState(leftOpVal.isSigned() == rightOpVal.isSigned(), "Invalid operation"); + return Bool(Arrays.equals(leftOpVal.getValue(), rightOpVal.getValue())); } @Override diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java index 2b5e889a96..a40843b2b6 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java @@ -52,33 +52,6 @@ public LitExpr eval(Valuation val) { return this; } - public BvLitExpr add(final BvLitExpr that) { - checkArgument(this.getType().equals(that.getType())); - BigInteger sum = BvUtils.bvLitExprToBigInteger(this).add(BvUtils.bvLitExprToBigInteger(that)); - return BvUtils.bigIntegerToBvLitExpr(sum, getType().getSize(), getType().isSigned()); - } - - public BvLitExpr sub(final BvLitExpr that) { - checkArgument(this.getType().equals(that.getType())); - BigInteger sub = BvUtils.bvLitExprToBigInteger(this).subtract(BvUtils.bvLitExprToBigInteger(that)); - return BvUtils.bigIntegerToBvLitExpr(sub, getType().getSize(), getType().isSigned()); - } - - public BvLitExpr neg() { - BigInteger neg = BvUtils.bvLitExprToBigInteger(this).negate(); - return BvUtils.bigIntegerToBvLitExpr(neg, getType().getSize(), getType().isSigned()); - } - - public BoolLitExpr eq(final BvLitExpr that) { - checkState(this.isSigned == that.isSigned, "Invalid operation"); - return Bool(Arrays.equals(this.value, that.value)); - } - - public BoolLitExpr neq(final BvLitExpr that) { - checkState(this.isSigned == that.isSigned, "Invalid operation"); - return Bool(!Arrays.equals(this.value, that.value)); - } - @Override public int hashCode() { int result = hashCode; diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java index f0ae56ca5a..49472121d8 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java @@ -42,6 +42,7 @@ public BvLitExpr eval(final Valuation val) { final BvLitExpr opVal = (BvLitExpr) op.eval(val); prod = prod.multiply(BvUtils.bvLitExprToBigInteger(opVal)); } + prod = BvUtils.fitBigIntegerIntoDomain(prod, getType().getSize(), getType().isSigned()); return BvUtils.bigIntegerToBvLitExpr(prod, getType().getSize(), getType().isSigned()); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java index 796329991c..a37b203211 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java @@ -3,6 +3,9 @@ import hu.bme.mit.theta.core.model.Valuation; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.abstracttype.NegExpr; +import hu.bme.mit.theta.core.utils.BvUtils; + +import java.math.BigInteger; import static com.google.common.base.Preconditions.checkArgument; import static hu.bme.mit.theta.core.utils.TypeUtils.cast; @@ -34,7 +37,9 @@ public BvType getType() { @Override public BvLitExpr eval(final Valuation val) { final BvLitExpr opVal = (BvLitExpr) getOp().eval(val); - return opVal.neg(); + BigInteger neg = BvUtils.bvLitExprToBigInteger(opVal).negate(); + neg = BvUtils.fitBigIntegerIntoDomain(neg, getType().getSize(), getType().isSigned()); + return BvUtils.bigIntegerToBvLitExpr(neg, getType().getSize(), getType().isSigned()); } @Override diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java index 0b6c00f736..485802f2f8 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java @@ -6,6 +6,9 @@ import hu.bme.mit.theta.core.type.booltype.BoolLitExpr; import hu.bme.mit.theta.core.type.booltype.BoolType; +import java.util.Arrays; + +import static com.google.common.base.Preconditions.checkState; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; import static hu.bme.mit.theta.core.utils.TypeUtils.cast; @@ -37,7 +40,9 @@ public BoolType getType() { public BoolLitExpr eval(final Valuation val) { final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); - return leftOpVal.neq(rightOpVal); + + checkState(leftOpVal.isSigned() == rightOpVal.isSigned(), "Invalid operation"); + return Bool(!Arrays.equals(leftOpVal.getValue(), rightOpVal.getValue())); } @Override diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java index ece0926f16..a846d7e051 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java @@ -40,7 +40,8 @@ public BvLitExpr eval(final Valuation val) { final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); - final BigInteger sub = BvUtils.bvLitExprToBigInteger(leftOpVal).subtract(BvUtils.bvLitExprToBigInteger(rightOpVal)); + BigInteger sub = BvUtils.bvLitExprToBigInteger(leftOpVal).subtract(BvUtils.bvLitExprToBigInteger(rightOpVal)); + sub = BvUtils.fitBigIntegerIntoDomain(sub, getType().getSize(), getType().isSigned()); return BvUtils.bigIntegerToBvLitExpr(sub, getType().getSize(), getType().isSigned()); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/BvUtils.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/BvUtils.java index c8a6205c37..3d8515a66b 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/BvUtils.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/BvUtils.java @@ -39,4 +39,27 @@ public static BvLitExpr bigIntegerToBvLitExpr(BigInteger integer, final int size return Bv(values, isSigned); } + + public static BigInteger fitBigIntegerIntoDomain(BigInteger integer, final int size, final boolean isSigned) { + if(isSigned) { + while(integer.compareTo(BigInteger.TWO.pow(size-1).negate()) < 0) { + integer = integer.add(BigInteger.TWO.pow(size)); + } + + while(integer.compareTo(BigInteger.TWO.pow(size-1)) >= 0) { + integer = integer.subtract(BigInteger.TWO.pow(size)); + } + } + else { + while(integer.compareTo(BigInteger.ZERO) < 0) { + integer = integer.add(BigInteger.TWO.pow(size)); + } + + while(integer.compareTo(BigInteger.TWO.pow(size)) >= 0) { + integer = integer.subtract(BigInteger.TWO.pow(size)); + } + } + + return integer; + } } From 278f00d582e92a581a021b630db5992e26211d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Dobos-Kov=C3=A1cs?= Date: Fri, 27 Mar 2020 20:30:36 +0100 Subject: [PATCH 05/23] Refactor --- .../mit/theta/core/type/bvtype/BvAddExpr.java | 12 +++-- .../mit/theta/core/type/bvtype/BvDivExpr.java | 4 +- .../mit/theta/core/type/bvtype/BvEqExpr.java | 3 +- .../mit/theta/core/type/bvtype/BvLitExpr.java | 44 +++++++++++++++++++ .../mit/theta/core/type/bvtype/BvMulExpr.java | 12 +++-- .../mit/theta/core/type/bvtype/BvNegExpr.java | 4 +- .../mit/theta/core/type/bvtype/BvNeqExpr.java | 3 +- .../mit/theta/core/type/bvtype/BvSubExpr.java | 4 +- 8 files changed, 59 insertions(+), 27 deletions(-) diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java index 5d97adc3a7..37df3445a9 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java @@ -40,13 +40,11 @@ public BvType getType() { @Override public BvLitExpr eval(final Valuation val) { - BigInteger sum = BigInteger.ZERO; - for (final Expr op : getOps()) { - final BvLitExpr opVal = (BvLitExpr) op.eval(val); - sum = sum.add(BvUtils.bvLitExprToBigInteger(opVal)); - } - sum = BvUtils.fitBigIntegerIntoDomain(sum, getType().getSize(), getType().isSigned()); - return BvUtils.bigIntegerToBvLitExpr(sum, getType().getSize(), getType().isSigned()); + return getOps().stream().skip(1).reduce( + (BvLitExpr) getOps().get(0).eval(val), + (op1, op2) -> (op1.add((BvLitExpr) op2.eval(val))), + BvLitExpr::add + ); } @Override diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java index e94e62cc37..021f54831d 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java @@ -39,9 +39,7 @@ public BvLitExpr eval(final Valuation val) { final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); - BigInteger div = BvUtils.bvLitExprToBigInteger(leftOpVal).divide(BvUtils.bvLitExprToBigInteger(rightOpVal)); - div = BvUtils.fitBigIntegerIntoDomain(div, getType().getSize(), getType().isSigned()); - return BvUtils.bigIntegerToBvLitExpr(div, getType().getSize(), getType().isSigned()); + return leftOpVal.div(rightOpVal); } @Override diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java index 0b3f909866..902099b42a 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java @@ -42,8 +42,7 @@ public BoolLitExpr eval(final Valuation val) { final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); - checkState(leftOpVal.isSigned() == rightOpVal.isSigned(), "Invalid operation"); - return Bool(Arrays.equals(leftOpVal.getValue(), rightOpVal.getValue())); + return leftOpVal.eq(rightOpVal); } @Override diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java index a40843b2b6..bd858b596d 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java @@ -52,6 +52,50 @@ public LitExpr eval(Valuation val) { return this; } + public BvLitExpr add(final BvLitExpr that) { + checkArgument(this.getType().equals(that.getType())); + BigInteger sum = BvUtils.bvLitExprToBigInteger(this).add(BvUtils.bvLitExprToBigInteger(that)); + sum = BvUtils.fitBigIntegerIntoDomain(sum, getType().getSize(), getType().isSigned()); + return BvUtils.bigIntegerToBvLitExpr(sum, getType().getSize(), getType().isSigned()); + } + + public BvLitExpr sub(final BvLitExpr that) { + checkArgument(this.getType().equals(that.getType())); + BigInteger sub = BvUtils.bvLitExprToBigInteger(this).subtract(BvUtils.bvLitExprToBigInteger(that)); + sub = BvUtils.fitBigIntegerIntoDomain(sub, getType().getSize(), getType().isSigned()); + return BvUtils.bigIntegerToBvLitExpr(sub, getType().getSize(), getType().isSigned()); + } + + public BvLitExpr mul(final BvLitExpr that) { + checkArgument(this.getType().equals(that.getType())); + BigInteger prod = BvUtils.bvLitExprToBigInteger(this).multiply(BvUtils.bvLitExprToBigInteger(that)); + prod = BvUtils.fitBigIntegerIntoDomain(prod, getType().getSize(), getType().isSigned()); + return BvUtils.bigIntegerToBvLitExpr(prod, getType().getSize(), getType().isSigned()); + } + + public BvLitExpr neg() { + BigInteger neg = BvUtils.bvLitExprToBigInteger(this).negate(); + neg = BvUtils.fitBigIntegerIntoDomain(neg, getType().getSize(), getType().isSigned()); + return BvUtils.bigIntegerToBvLitExpr(neg, getType().getSize(), getType().isSigned()); + } + + public BvLitExpr div(final BvLitExpr that) { + checkArgument(this.getType().equals(that.getType())); + BigInteger div = BvUtils.bvLitExprToBigInteger(this).divide(BvUtils.bvLitExprToBigInteger(that)); + div = BvUtils.fitBigIntegerIntoDomain(div, getType().getSize(), getType().isSigned()); + return BvUtils.bigIntegerToBvLitExpr(div, getType().getSize(), getType().isSigned()); + } + + public BoolLitExpr eq(final BvLitExpr that) { + checkArgument(this.getType().equals(that.getType())); + return Bool(Arrays.equals(this.getValue(), that.getValue())); + } + + public BoolLitExpr neq(final BvLitExpr that) { + checkArgument(this.getType().equals(that.getType())); + return Bool(!Arrays.equals(this.getValue(), that.getValue())); + } + @Override public int hashCode() { int result = hashCode; diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java index 49472121d8..042a977dce 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java @@ -37,13 +37,11 @@ public BvType getType() { @Override public BvLitExpr eval(final Valuation val) { - BigInteger prod = BigInteger.ONE; - for (final Expr op : getOps()) { - final BvLitExpr opVal = (BvLitExpr) op.eval(val); - prod = prod.multiply(BvUtils.bvLitExprToBigInteger(opVal)); - } - prod = BvUtils.fitBigIntegerIntoDomain(prod, getType().getSize(), getType().isSigned()); - return BvUtils.bigIntegerToBvLitExpr(prod, getType().getSize(), getType().isSigned()); + return getOps().stream().skip(1).reduce( + (BvLitExpr) getOps().get(0).eval(val), + (op1, op2) -> (op1.mul((BvLitExpr) op2.eval(val))), + BvLitExpr::mul + ); } @Override diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java index a37b203211..fde625a277 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java @@ -37,9 +37,7 @@ public BvType getType() { @Override public BvLitExpr eval(final Valuation val) { final BvLitExpr opVal = (BvLitExpr) getOp().eval(val); - BigInteger neg = BvUtils.bvLitExprToBigInteger(opVal).negate(); - neg = BvUtils.fitBigIntegerIntoDomain(neg, getType().getSize(), getType().isSigned()); - return BvUtils.bigIntegerToBvLitExpr(neg, getType().getSize(), getType().isSigned()); + return opVal.neg(); } @Override diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java index 485802f2f8..2c5261521f 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java @@ -41,8 +41,7 @@ public BoolLitExpr eval(final Valuation val) { final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); - checkState(leftOpVal.isSigned() == rightOpVal.isSigned(), "Invalid operation"); - return Bool(!Arrays.equals(leftOpVal.getValue(), rightOpVal.getValue())); + return leftOpVal.neq(rightOpVal); } @Override diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java index a846d7e051..c357b5ff90 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java @@ -40,9 +40,7 @@ public BvLitExpr eval(final Valuation val) { final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); - BigInteger sub = BvUtils.bvLitExprToBigInteger(leftOpVal).subtract(BvUtils.bvLitExprToBigInteger(rightOpVal)); - sub = BvUtils.fitBigIntegerIntoDomain(sub, getType().getSize(), getType().isSigned()); - return BvUtils.bigIntegerToBvLitExpr(sub, getType().getSize(), getType().isSigned()); + return leftOpVal.sub(rightOpVal); } @Override From a365dac3c9d808f7d05407d408d3b19cc866a035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Dobos-Kov=C3=A1cs?= Date: Fri, 27 Mar 2020 21:16:12 +0100 Subject: [PATCH 06/23] Basic bitvector support: relational operators --- subprojects/cfa/src/test/resources/bv.cfa | 12 +-- .../mit/theta/core/type/bvtype/BvExprs.java | 16 ++++ .../mit/theta/core/type/bvtype/BvGeqExpr.java | 85 +++++++++++++++++++ .../mit/theta/core/type/bvtype/BvGtExpr.java | 85 +++++++++++++++++++ .../mit/theta/core/type/bvtype/BvLeqExpr.java | 85 +++++++++++++++++++ .../mit/theta/core/type/bvtype/BvLitExpr.java | 20 +++++ .../mit/theta/core/type/bvtype/BvLtExpr.java | 84 ++++++++++++++++++ .../mit/theta/core/type/bvtype/BvType.java | 22 ++++- .../theta/solver/z3/Z3ExprTransformer.java | 60 ++++++++++++- .../bme/mit/theta/solver/z3/Z3SolverTest.java | 22 +++++ 10 files changed, 482 insertions(+), 9 deletions(-) create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGeqExpr.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGtExpr.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLeqExpr.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLtExpr.java diff --git a/subprojects/cfa/src/test/resources/bv.cfa b/subprojects/cfa/src/test/resources/bv.cfa index 17a88c4c9a..77048656f2 100644 --- a/subprojects/cfa/src/test/resources/bv.cfa +++ b/subprojects/cfa/src/test/resources/bv.cfa @@ -8,10 +8,10 @@ main process cfa { final loc END error loc ERR - L0 -> L1 { x := 4'd1 } - L1 -> L2 { assume x /= 4'd5 } - L1 -> L3 { assume x = 4'd5 } - L2 -> L1 { x := x * 4'd2 } - L3 -> END { assume x /= 4'd5 } - L3 -> ERR { assume not (x /= 4'd5) } + L0 -> L1 { x := 4'd0 } + L1 -> L2 { assume x < 4'd5 } + L1 -> L3 { assume not (x < 4'd5) } + L2 -> L1 { x := x + 4'd1 } + L3 -> END { assume x <= 4'd5 } + L3 -> ERR { assume not (x <= 4'd5) } } \ No newline at end of file diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java index 746cbd740d..c1970455a1 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java @@ -48,4 +48,20 @@ public static BvEqExpr Eq(final Expr leftOp, final Expr rightOp) public static BvNeqExpr Neq(final Expr leftOp, final Expr rightOp) { return BvNeqExpr.of(leftOp, rightOp); } + + public static BvLtExpr Lt(final Expr leftOp, final Expr rightOp) { + return BvLtExpr.of(leftOp, rightOp); + } + + public static BvLeqExpr Leq(final Expr leftOp, final Expr rightOp) { + return BvLeqExpr.of(leftOp, rightOp); + } + + public static BvGtExpr Gt(final Expr leftOp, final Expr rightOp) { + return BvGtExpr.of(leftOp, rightOp); + } + + public static BvGeqExpr Geq(final Expr leftOp, final Expr rightOp) { + return BvGeqExpr.of(leftOp, rightOp); + } } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGeqExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGeqExpr.java new file mode 100644 index 0000000000..a2d30e89ea --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGeqExpr.java @@ -0,0 +1,85 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.LitExpr; +import hu.bme.mit.theta.core.type.abstracttype.GeqExpr; +import hu.bme.mit.theta.core.type.abstracttype.LtExpr; +import hu.bme.mit.theta.core.type.booltype.BoolType; + +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class BvGeqExpr extends GeqExpr { + + private static final int HASH_SEED = 6234; + private static final String OPERATOR_LABEL = ">="; + + private BvGeqExpr(final Expr leftOp, final Expr rightOp) { + super(leftOp, rightOp); + } + + public static BvGeqExpr of(final Expr leftOp, final Expr rightOp) { + return new BvGeqExpr(leftOp, rightOp); + } + + public static BvGeqExpr create(final Expr leftOp, final Expr rightOp) { + final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); + final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + return BvGeqExpr.of(newLeftOp, newRightOp); + } + + @Override + public BoolType getType() { + return Bool(); + } + + @Override + public LitExpr eval(final Valuation val) { + final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); + final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); + return leftOpVal.geq(rightOpVal); + } + + @Override + public BvGeqExpr with(final Expr leftOp, final Expr rightOp) { + if (leftOp == getLeftOp() && rightOp == getRightOp()) { + return this; + } else { + return BvGeqExpr.of(leftOp, rightOp); + } + } + + @Override + public BvGeqExpr withLeftOp(final Expr leftOp) { + return with(leftOp, getRightOp()); + } + + @Override + public BvGeqExpr withRightOp(final Expr rightOp) { + return with(getLeftOp(), rightOp); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvGeqExpr) { + final BvGeqExpr that = (BvGeqExpr) obj; + return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } + +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGtExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGtExpr.java new file mode 100644 index 0000000000..364a472dad --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGtExpr.java @@ -0,0 +1,85 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.LitExpr; +import hu.bme.mit.theta.core.type.abstracttype.GtExpr; +import hu.bme.mit.theta.core.type.abstracttype.LtExpr; +import hu.bme.mit.theta.core.type.booltype.BoolType; + +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class BvGtExpr extends GtExpr { + + private static final int HASH_SEED = 6231; + private static final String OPERATOR_LABEL = ">"; + + private BvGtExpr(final Expr leftOp, final Expr rightOp) { + super(leftOp, rightOp); + } + + public static BvGtExpr of(final Expr leftOp, final Expr rightOp) { + return new BvGtExpr(leftOp, rightOp); + } + + public static BvGtExpr create(final Expr leftOp, final Expr rightOp) { + final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); + final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + return BvGtExpr.of(newLeftOp, newRightOp); + } + + @Override + public BoolType getType() { + return Bool(); + } + + @Override + public LitExpr eval(final Valuation val) { + final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); + final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); + return leftOpVal.gt(rightOpVal); + } + + @Override + public BvGtExpr with(final Expr leftOp, final Expr rightOp) { + if (leftOp == getLeftOp() && rightOp == getRightOp()) { + return this; + } else { + return BvGtExpr.of(leftOp, rightOp); + } + } + + @Override + public BvGtExpr withLeftOp(final Expr leftOp) { + return with(leftOp, getRightOp()); + } + + @Override + public BvGtExpr withRightOp(final Expr rightOp) { + return with(getLeftOp(), rightOp); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvGtExpr) { + final BvGtExpr that = (BvGtExpr) obj; + return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } + +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLeqExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLeqExpr.java new file mode 100644 index 0000000000..9b988b869f --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLeqExpr.java @@ -0,0 +1,85 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.LitExpr; +import hu.bme.mit.theta.core.type.abstracttype.LeqExpr; +import hu.bme.mit.theta.core.type.abstracttype.LtExpr; +import hu.bme.mit.theta.core.type.booltype.BoolType; + +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class BvLeqExpr extends LeqExpr { + + private static final int HASH_SEED = 1458; + private static final String OPERATOR_LABEL = "<="; + + private BvLeqExpr(final Expr leftOp, final Expr rightOp) { + super(leftOp, rightOp); + } + + public static BvLeqExpr of(final Expr leftOp, final Expr rightOp) { + return new BvLeqExpr(leftOp, rightOp); + } + + public static BvLeqExpr create(final Expr leftOp, final Expr rightOp) { + final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); + final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + return BvLeqExpr.of(newLeftOp, newRightOp); + } + + @Override + public BoolType getType() { + return Bool(); + } + + @Override + public LitExpr eval(final Valuation val) { + final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); + final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); + return leftOpVal.leq(rightOpVal); + } + + @Override + public BvLeqExpr with(final Expr leftOp, final Expr rightOp) { + if (leftOp == getLeftOp() && rightOp == getRightOp()) { + return this; + } else { + return BvLeqExpr.of(leftOp, rightOp); + } + } + + @Override + public BvLeqExpr withLeftOp(final Expr leftOp) { + return with(leftOp, getRightOp()); + } + + @Override + public BvLeqExpr withRightOp(final Expr rightOp) { + return with(getLeftOp(), rightOp); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvLeqExpr) { + final BvLeqExpr that = (BvLeqExpr) obj; + return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } + +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java index bd858b596d..face4ca19f 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java @@ -96,6 +96,26 @@ public BoolLitExpr neq(final BvLitExpr that) { return Bool(!Arrays.equals(this.getValue(), that.getValue())); } + public BoolLitExpr lt(final BvLitExpr that) { + checkArgument(this.getType().equals(that.getType())); + return Bool(BvUtils.bvLitExprToBigInteger(this).compareTo(BvUtils.bvLitExprToBigInteger(that)) < 0); + } + + public BoolLitExpr leq(final BvLitExpr that) { + checkArgument(this.getType().equals(that.getType())); + return Bool(BvUtils.bvLitExprToBigInteger(this).compareTo(BvUtils.bvLitExprToBigInteger(that)) <= 0); + } + + public BoolLitExpr gt(final BvLitExpr that) { + checkArgument(this.getType().equals(that.getType())); + return Bool(BvUtils.bvLitExprToBigInteger(this).compareTo(BvUtils.bvLitExprToBigInteger(that)) > 0); + } + + public BoolLitExpr geq(final BvLitExpr that) { + checkArgument(this.getType().equals(that.getType())); + return Bool(BvUtils.bvLitExprToBigInteger(this).compareTo(BvUtils.bvLitExprToBigInteger(that)) >= 0); + } + @Override public int hashCode() { int result = hashCode; diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLtExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLtExpr.java new file mode 100644 index 0000000000..cb4f8ad010 --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLtExpr.java @@ -0,0 +1,84 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.LitExpr; +import hu.bme.mit.theta.core.type.abstracttype.LtExpr; +import hu.bme.mit.theta.core.type.booltype.BoolType; + +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class BvLtExpr extends LtExpr { + + private static final int HASH_SEED = 2798; + private static final String OPERATOR_LABEL = "<"; + + private BvLtExpr(final Expr leftOp, final Expr rightOp) { + super(leftOp, rightOp); + } + + public static BvLtExpr of(final Expr leftOp, final Expr rightOp) { + return new BvLtExpr(leftOp, rightOp); + } + + public static BvLtExpr create(final Expr leftOp, final Expr rightOp) { + final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); + final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + return BvLtExpr.of(newLeftOp, newRightOp); + } + + @Override + public BoolType getType() { + return Bool(); + } + + @Override + public LitExpr eval(final Valuation val) { + final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); + final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); + return leftOpVal.lt(rightOpVal); + } + + @Override + public BvLtExpr with(final Expr leftOp, final Expr rightOp) { + if (leftOp == getLeftOp() && rightOp == getRightOp()) { + return this; + } else { + return BvLtExpr.of(leftOp, rightOp); + } + } + + @Override + public BvLtExpr withLeftOp(final Expr leftOp) { + return with(leftOp, getRightOp()); + } + + @Override + public BvLtExpr withRightOp(final Expr rightOp) { + return with(getLeftOp(), rightOp); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvLtExpr) { + final BvLtExpr that = (BvLtExpr) obj; + return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } + +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java index e99beaa06c..48c3e2698e 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java @@ -6,7 +6,7 @@ import static com.google.common.base.Preconditions.checkArgument; -public final class BvType implements Additive, Multiplicative, Equational { +public final class BvType implements Additive, Multiplicative, Equational, Ordered { private final static int HASH_SEED = 5674; private final static String TYPE_LABEL = "Bv"; @@ -68,6 +68,26 @@ public NeqExpr Neq(Expr leftOp, Expr rightOp) { return BvNeqExpr.of(leftOp, rightOp); } + @Override + public LtExpr Lt(Expr leftOp, Expr rightOp) { + return BvLtExpr.of(leftOp, rightOp); + } + + @Override + public LeqExpr Leq(Expr leftOp, Expr rightOp) { + return BvLeqExpr.of(leftOp, rightOp); + } + + @Override + public GtExpr Gt(Expr leftOp, Expr rightOp) { + return BvGtExpr.of(leftOp, rightOp); + } + + @Override + public GeqExpr Geq(Expr leftOp, Expr rightOp) { + return BvGeqExpr.of(leftOp, rightOp); + } + @Override public int hashCode() { int result = hashCode; diff --git a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java index 5c8f35f2fa..62ad8ee587 100644 --- a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java +++ b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java @@ -199,13 +199,21 @@ public Z3ExprTransformer(final Z3TransformationManager transformer, final Contex .addCase(BvNegExpr.class, this::transformBvNeg) + .addCase(BvMulExpr.class, this::transformBvMul) + + .addCase(BvDivExpr.class, this::transformBvDiv) + .addCase(BvEqExpr.class, this::transformBvEq) .addCase(BvNeqExpr.class, this::transformBvNeq) - .addCase(BvMulExpr.class, this::transformBvMul) + .addCase(BvGeqExpr.class, this::transformBvGeq) - .addCase(BvDivExpr.class, this::transformBvDiv) + .addCase(BvGtExpr.class, this::transformBvGt) + + .addCase(BvLeqExpr.class, this::transformBvLeq) + + .addCase(BvLtExpr.class, this::transformBvLt) // Functions @@ -566,6 +574,54 @@ private com.microsoft.z3.Expr transformBvDiv(final BvDivExpr expr) { } } + private com.microsoft.z3.Expr transformBvGeq(final BvGeqExpr expr) { + final com.microsoft.z3.BitVecExpr leftOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getLeftOp()); + final com.microsoft.z3.BitVecExpr rightOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getRightOp()); + + if(expr.getLeftOp().getType().isSigned()) { + return context.mkBVSGE(leftOpTerm, rightOpTerm); + } + else { + return context.mkBVUGE(leftOpTerm, rightOpTerm); + } + } + + private com.microsoft.z3.Expr transformBvGt(final BvGtExpr expr) { + final com.microsoft.z3.BitVecExpr leftOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getLeftOp()); + final com.microsoft.z3.BitVecExpr rightOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getRightOp()); + + if(expr.getLeftOp().getType().isSigned()) { + return context.mkBVSGT(leftOpTerm, rightOpTerm); + } + else { + return context.mkBVUGT(leftOpTerm, rightOpTerm); + } + } + + private com.microsoft.z3.Expr transformBvLeq(final BvLeqExpr expr) { + final com.microsoft.z3.BitVecExpr leftOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getLeftOp()); + final com.microsoft.z3.BitVecExpr rightOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getRightOp()); + + if(expr.getLeftOp().getType().isSigned()) { + return context.mkBVSLE(leftOpTerm, rightOpTerm); + } + else { + return context.mkBVULE(leftOpTerm, rightOpTerm); + } + } + + private com.microsoft.z3.Expr transformBvLt(final BvLtExpr expr) { + final com.microsoft.z3.BitVecExpr leftOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getLeftOp()); + final com.microsoft.z3.BitVecExpr rightOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getRightOp()); + + if(expr.getLeftOp().getType().isSigned()) { + return context.mkBVSLT(leftOpTerm, rightOpTerm); + } + else { + return context.mkBVULT(leftOpTerm, rightOpTerm); + } + } + /* * Arrays */ diff --git a/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java b/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java index ed86498860..7739311e3b 100644 --- a/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java +++ b/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java @@ -242,4 +242,26 @@ public void testBV6() { solver.pop(); } + @Test + public void testBV7() { + final Solver solver = Z3SolverFactory.getInstace().createSolver(); + + final ConstDecl cx = Const("x", BvType(4, true)); + final ConstDecl cy = Const("y", BvType(4, false)); + + solver.push(); + + solver.add(BvExprs.Lt(cx.getRef(), Bv(new boolean[] {true, true, true, true}, true))); + solver.add(BvExprs.Lt(cy.getRef(), Bv(new boolean[] {true, true, true, true}, false))); + + SolverStatus status = solver.check(); + assertTrue(status.isSat()); + + Valuation model = solver.getModel(); + assertNotNull(model); + assertNotNull(model.toMap()); + + solver.pop(); + } + } From 016a5512275b427d94eda2a4c82421a689769ca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Dobos-Kov=C3=A1cs?= Date: Thu, 2 Apr 2020 11:08:57 +0200 Subject: [PATCH 07/23] Basic bitvector support: rem and mod operators --- .../bme/mit/theta/cfa/dsl/CfaExpression.java | 37 ++------- subprojects/cfa/src/test/resources/bv.cfa | 2 +- .../core/dsl/impl/ExprCreatorVisitor.java | 8 +- .../mit/theta/core/dsl/impl/ExprWriter.java | 8 +- .../theta/core/parser/CoreInterpreter.java | 8 +- .../core/type/abstracttype/AbstractExprs.java | 20 +++++ .../core/type/abstracttype/Divisible.java | 11 +++ .../theta/core/type/abstracttype/ModExpr.java | 20 +++++ .../theta/core/type/abstracttype/RemExpr.java | 20 +++++ .../mit/theta/core/type/bvtype/BvExprs.java | 8 ++ .../mit/theta/core/type/bvtype/BvLitExpr.java | 44 ++++++++++ .../mit/theta/core/type/bvtype/BvModExpr.java | 81 ++++++++++++++++++ .../mit/theta/core/type/bvtype/BvRemExpr.java | 82 +++++++++++++++++++ .../mit/theta/core/type/bvtype/BvType.java | 13 ++- .../mit/theta/core/type/inttype/IntExprs.java | 8 +- .../inttype/{ModExpr.java => IntModExpr.java} | 25 +++--- .../inttype/{RemExpr.java => IntRemExpr.java} | 25 +++--- .../mit/theta/core/type/inttype/IntType.java | 19 +++-- .../mit/theta/core/utils/ExprSimplifier.java | 6 +- .../theta/solver/z3/Z3ExprTransformer.java | 42 ++++++++-- .../bme/mit/theta/solver/z3/Z3SolverTest.java | 22 +++++ .../theta/sts/dsl/StsExprCreatorVisitor.java | 8 +- .../bme/mit/theta/xta/dsl/XtaExpression.java | 4 +- 23 files changed, 426 insertions(+), 95 deletions(-) create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/abstracttype/Divisible.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/abstracttype/ModExpr.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/abstracttype/RemExpr.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvModExpr.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvRemExpr.java rename subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/{ModExpr.java => IntModExpr.java} (72%) rename subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/{RemExpr.java => IntRemExpr.java} (72%) diff --git a/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java b/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java index 57acc4eff2..723420740c 100644 --- a/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java +++ b/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java @@ -23,18 +23,7 @@ import static hu.bme.mit.theta.common.Utils.singleElementOf; import static hu.bme.mit.theta.common.Utils.tail; import static hu.bme.mit.theta.core.decl.Decls.Param; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Add; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Div; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Eq; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Geq; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Gt; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Ite; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Leq; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Lt; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Mul; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Neg; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Neq; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Sub; +import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.*; import static hu.bme.mit.theta.core.type.anytype.Exprs.Prime; import static hu.bme.mit.theta.core.type.arraytype.ArrayExprs.Read; import static hu.bme.mit.theta.core.type.arraytype.ArrayExprs.Write; @@ -50,8 +39,6 @@ import static hu.bme.mit.theta.core.type.booltype.BoolExprs.True; import static hu.bme.mit.theta.core.type.bvtype.BvExprs.Bv; import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; -import static hu.bme.mit.theta.core.type.inttype.IntExprs.Mod; -import static hu.bme.mit.theta.core.type.inttype.IntExprs.Rem; import static hu.bme.mit.theta.core.type.rattype.RatExprs.Rat; import static hu.bme.mit.theta.core.utils.TypeUtils.cast; import static java.util.stream.Collectors.toList; @@ -62,12 +49,12 @@ import java.util.List; import java.util.stream.Stream; +import hu.bme.mit.theta.core.type.abstracttype.*; import org.antlr.v4.runtime.Token; import com.google.common.collect.ImmutableList; import hu.bme.mit.theta.cfa.dsl.gen.CfaDslBaseVisitor; -import hu.bme.mit.theta.cfa.dsl.gen.CfaDslParser; import hu.bme.mit.theta.cfa.dsl.gen.CfaDslParser.AccessContext; import hu.bme.mit.theta.cfa.dsl.gen.CfaDslParser.AccessorExprContext; import hu.bme.mit.theta.cfa.dsl.gen.CfaDslParser.AdditiveExprContext; @@ -104,10 +91,6 @@ import hu.bme.mit.theta.core.dsl.DeclSymbol; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.Type; -import hu.bme.mit.theta.core.type.abstracttype.AddExpr; -import hu.bme.mit.theta.core.type.abstracttype.DivExpr; -import hu.bme.mit.theta.core.type.abstracttype.MulExpr; -import hu.bme.mit.theta.core.type.abstracttype.SubExpr; import hu.bme.mit.theta.core.type.anytype.RefExpr; import hu.bme.mit.theta.core.type.arraytype.ArrayType; import hu.bme.mit.theta.core.type.booltype.BoolType; @@ -116,8 +99,8 @@ import hu.bme.mit.theta.core.type.functype.FuncExprs; import hu.bme.mit.theta.core.type.inttype.IntLitExpr; import hu.bme.mit.theta.core.type.inttype.IntType; -import hu.bme.mit.theta.core.type.inttype.ModExpr; -import hu.bme.mit.theta.core.type.inttype.RemExpr; +import hu.bme.mit.theta.core.type.inttype.IntModExpr; +import hu.bme.mit.theta.core.type.inttype.IntRemExpr; import hu.bme.mit.theta.core.type.rattype.RatLitExpr; import hu.bme.mit.theta.core.utils.TypeUtils; @@ -484,16 +467,12 @@ private DivExpr createDivExpr(final Expr leftOp, final Expr rightOp) { return Div(leftOp, rightOp); } - private ModExpr createModExpr(final Expr uncastLeftOp, final Expr uncastRightOp) { - final Expr leftOp = TypeUtils.cast(uncastLeftOp, Int()); - final Expr rightOp = TypeUtils.cast(uncastRightOp, Int()); - return Mod(leftOp, rightOp); + private ModExpr createModExpr(final Expr uncastLeftOp, final Expr uncastRightOp) { + return Mod(uncastLeftOp, uncastRightOp); } - private RemExpr createRemExpr(final Expr uncastLeftOp, final Expr uncastRightOp) { - final Expr leftOp = TypeUtils.cast(uncastLeftOp, Int()); - final Expr rightOp = TypeUtils.cast(uncastRightOp, Int()); - return Rem(leftOp, rightOp); + private RemExpr createRemExpr(final Expr uncastLeftOp, final Expr uncastRightOp) { + return Rem(uncastLeftOp, uncastRightOp); } //// diff --git a/subprojects/cfa/src/test/resources/bv.cfa b/subprojects/cfa/src/test/resources/bv.cfa index 77048656f2..2fc0a45420 100644 --- a/subprojects/cfa/src/test/resources/bv.cfa +++ b/subprojects/cfa/src/test/resources/bv.cfa @@ -11,7 +11,7 @@ main process cfa { L0 -> L1 { x := 4'd0 } L1 -> L2 { assume x < 4'd5 } L1 -> L3 { assume not (x < 4'd5) } - L2 -> L1 { x := x + 4'd1 } + L2 -> L1 { x := (x + 4'd1) mod 4'd5 } L3 -> END { assume x <= 4'd5 } L3 -> ERR { assume not (x <= 4'd5) } } \ No newline at end of file diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/dsl/impl/ExprCreatorVisitor.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/dsl/impl/ExprCreatorVisitor.java index 3a804ab68f..98510bccee 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/dsl/impl/ExprCreatorVisitor.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/dsl/impl/ExprCreatorVisitor.java @@ -104,8 +104,8 @@ import hu.bme.mit.theta.core.type.functype.FuncExprs; import hu.bme.mit.theta.core.type.inttype.IntLitExpr; import hu.bme.mit.theta.core.type.inttype.IntType; -import hu.bme.mit.theta.core.type.inttype.ModExpr; -import hu.bme.mit.theta.core.type.inttype.RemExpr; +import hu.bme.mit.theta.core.type.inttype.IntModExpr; +import hu.bme.mit.theta.core.type.inttype.IntRemExpr; import hu.bme.mit.theta.core.type.rattype.RatLitExpr; import hu.bme.mit.theta.core.utils.TypeUtils; @@ -441,13 +441,13 @@ private DivExpr createDivExpr(final Expr leftOp, final Expr rightOp) { return Div(leftOp, rightOp); } - private ModExpr createModExpr(final Expr uncastLeftOp, final Expr uncastRightOp) { + private IntModExpr createModExpr(final Expr uncastLeftOp, final Expr uncastRightOp) { final Expr leftOp = TypeUtils.cast(uncastLeftOp, Int()); final Expr rightOp = TypeUtils.cast(uncastRightOp, Int()); return Mod(leftOp, rightOp); } - private RemExpr createRemExpr(final Expr uncastLeftOp, final Expr uncastRightOp) { + private IntRemExpr createRemExpr(final Expr uncastLeftOp, final Expr uncastRightOp) { final Expr leftOp = TypeUtils.cast(uncastLeftOp, Int()); final Expr rightOp = TypeUtils.cast(uncastRightOp, Int()); return Rem(leftOp, rightOp); diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/dsl/impl/ExprWriter.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/dsl/impl/ExprWriter.java index b403814b1d..9875fd3b9a 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/dsl/impl/ExprWriter.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/dsl/impl/ExprWriter.java @@ -48,8 +48,8 @@ import hu.bme.mit.theta.core.type.inttype.IntNeqExpr; import hu.bme.mit.theta.core.type.inttype.IntSubExpr; import hu.bme.mit.theta.core.type.inttype.IntToRatExpr; -import hu.bme.mit.theta.core.type.inttype.ModExpr; -import hu.bme.mit.theta.core.type.inttype.RemExpr; +import hu.bme.mit.theta.core.type.inttype.IntModExpr; +import hu.bme.mit.theta.core.type.inttype.IntRemExpr; import hu.bme.mit.theta.core.type.rattype.RatAddExpr; import hu.bme.mit.theta.core.type.rattype.RatDivExpr; import hu.bme.mit.theta.core.type.rattype.RatEqExpr; @@ -112,9 +112,9 @@ private ExprWriter() { .addCase(IntDivExpr.class, e -> infixBinary(e, " / ")) - .addCase(ModExpr.class, e -> infixBinary(e, " mod ")) + .addCase(IntModExpr.class, e -> infixBinary(e, " mod ")) - .addCase(RemExpr.class, e -> infixBinary(e, " rem ")) + .addCase(IntRemExpr.class, e -> infixBinary(e, " rem ")) .addCase(IntEqExpr.class, e -> infixBinary(e, " = ")) diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/parser/CoreInterpreter.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/parser/CoreInterpreter.java index 553a1a98aa..81a4f7ddbe 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/parser/CoreInterpreter.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/parser/CoreInterpreter.java @@ -74,8 +74,8 @@ import hu.bme.mit.theta.core.type.functype.FuncAppExpr; import hu.bme.mit.theta.core.type.functype.FuncType; import hu.bme.mit.theta.core.type.inttype.IntType; -import hu.bme.mit.theta.core.type.inttype.ModExpr; -import hu.bme.mit.theta.core.type.inttype.RemExpr; +import hu.bme.mit.theta.core.type.inttype.IntModExpr; +import hu.bme.mit.theta.core.type.inttype.IntRemExpr; import hu.bme.mit.theta.core.type.rattype.RatType; public class CoreInterpreter { @@ -108,8 +108,8 @@ public void defineCommonExprs() { defineExpr("ite", exprTernaryOperator(IteExpr::create)); defineExpr("read", exprBinaryOperator(ArrayReadExpr::create)); defineExpr("write", exprTernaryOperator(ArrayWriteExpr::create)); - defineExpr("mod", exprBinaryOperator(ModExpr::create)); - defineExpr("rem", exprBinaryOperator(RemExpr::create)); + defineExpr("mod", exprBinaryOperator(IntModExpr::create)); + defineExpr("rem", exprBinaryOperator(IntRemExpr::create)); defineExpr("+", exprMultiaryOperator(AddExpr::create2)); defineExpr("-", exprBinaryOperator(SubExpr::create2)); defineExpr("*", exprMultiaryOperator(MulExpr::create2)); diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/abstracttype/AbstractExprs.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/abstracttype/AbstractExprs.java index 96b1442c6b..8a6452ec86 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/abstracttype/AbstractExprs.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/abstracttype/AbstractExprs.java @@ -156,6 +156,26 @@ public static > DivExpr Div(final Expr leftOp, return type.Div(newLeftOp, newRightOp); } + /* + * Divisible + */ + + public static > ModExpr Mod(final Expr leftOp, final Expr rightOp) { + final Tuple2, Expr> newOps = unify(leftOp, rightOp); + final Expr newLeftOp = newOps.get1(); + final Expr newRightOp = newOps.get2(); + final T type = newLeftOp.getType(); + return type.Mod(newLeftOp, newRightOp); + } + + public static > RemExpr Rem(final Expr leftOp, final Expr rightOp) { + final Tuple2, Expr> newOps = unify(leftOp, rightOp); + final Expr newLeftOp = newOps.get1(); + final Expr newRightOp = newOps.get2(); + final T type = newLeftOp.getType(); + return type.Rem(newLeftOp, newRightOp); + } + /* * Equational */ diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/abstracttype/Divisible.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/abstracttype/Divisible.java new file mode 100644 index 0000000000..13fad83858 --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/abstracttype/Divisible.java @@ -0,0 +1,11 @@ +package hu.bme.mit.theta.core.type.abstracttype; + +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.Type; + +public interface Divisible> extends Type { + + ModExpr Mod(Expr leftOp, Expr rightOp); + + RemExpr Rem(Expr leftOp, Expr rightOp); +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/abstracttype/ModExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/abstracttype/ModExpr.java new file mode 100644 index 0000000000..8d71396fa8 --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/abstracttype/ModExpr.java @@ -0,0 +1,20 @@ +package hu.bme.mit.theta.core.type.abstracttype; + +import hu.bme.mit.theta.core.type.BinaryExpr; +import hu.bme.mit.theta.core.type.Expr; + +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public abstract class ModExpr> extends BinaryExpr { + + protected ModExpr(final Expr leftOp, final Expr rightOp) { + super(leftOp, rightOp); + } + + public static > ModExpr create2(final Expr leftOp, final Expr rightOp) { + @SuppressWarnings("unchecked") final ExprType type = (ExprType) leftOp.getType(); + final Expr newLeftOp = cast(leftOp, type); + final Expr newRightOp = cast(rightOp, type); + return type.Mod(newLeftOp, newRightOp); + } +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/abstracttype/RemExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/abstracttype/RemExpr.java new file mode 100644 index 0000000000..13d521cc52 --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/abstracttype/RemExpr.java @@ -0,0 +1,20 @@ +package hu.bme.mit.theta.core.type.abstracttype; + +import hu.bme.mit.theta.core.type.BinaryExpr; +import hu.bme.mit.theta.core.type.Expr; + +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public abstract class RemExpr> extends BinaryExpr { + + protected RemExpr(final Expr leftOp, final Expr rightOp) { + super(leftOp, rightOp); + } + + public static > RemExpr create2(final Expr leftOp, final Expr rightOp) { + @SuppressWarnings("unchecked") final ExprType type = (ExprType) leftOp.getType(); + final Expr newLeftOp = cast(leftOp, type); + final Expr newRightOp = cast(rightOp, type); + return type.Rem(newLeftOp, newRightOp); + } +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java index c1970455a1..fbb495abb6 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java @@ -41,6 +41,14 @@ public static BvDivExpr Div(final Expr leftOp, final Expr rightO return BvDivExpr.of(leftOp, rightOp); } + public static BvModExpr Mod(final Expr leftOp, final Expr rightOp) { + return BvModExpr.of(leftOp, rightOp); + } + + public static BvRemExpr Rem(final Expr leftOp, final Expr rightOp) { + return BvRemExpr.of(leftOp, rightOp); + } + public static BvEqExpr Eq(final Expr leftOp, final Expr rightOp) { return BvEqExpr.of(leftOp, rightOp); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java index face4ca19f..98df65c024 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java @@ -86,6 +86,50 @@ public BvLitExpr div(final BvLitExpr that) { return BvUtils.bigIntegerToBvLitExpr(div, getType().getSize(), getType().isSigned()); } + public BvLitExpr mod(final BvLitExpr that) { + checkArgument(this.getType().equals(that.getType())); + // Always positive semantics: + // 5 mod 3 = 2 + // 5 mod -3 = 2 + // -5 mod 3 = 1 + // -5 mod -3 = 1 + BigInteger result = BvUtils.bvLitExprToBigInteger(this).mod(BvUtils.bvLitExprToBigInteger(that)); + if (result.compareTo(BigInteger.ZERO) < 0) { + result = result.add(BvUtils.bvLitExprToBigInteger(that).abs()); + } + assert result.compareTo(BigInteger.ZERO) >= 0; + return BvUtils.bigIntegerToBvLitExpr(result, getType().getSize(), getType().isSigned()); + } + + public BvLitExpr rem(final BvLitExpr that) { + // Semantics: + // 5 rem 3 = 2 + // 5 rem -3 = -2 + // -5 rem 3 = 1 + // -5 rem -3 = -1 + BigInteger thisInt = BvUtils.bvLitExprToBigInteger(this); + BigInteger thatInt = BvUtils.bvLitExprToBigInteger(that); + BigInteger thisAbs = thisInt.abs(); + BigInteger thatAbs = thatInt.abs(); + if (thisInt.compareTo(BigInteger.ZERO) < 0 && thatInt.compareTo(BigInteger.ZERO) < 0) { + BigInteger result = thisAbs.mod(thatAbs); + if (result.compareTo(BigInteger.ZERO) != 0) { + result = result.subtract(thatAbs); + } + return BvUtils.bigIntegerToBvLitExpr(result, getType().getSize(), getType().isSigned()); + } else if (thisInt.compareTo(BigInteger.ZERO) >= 0 && thatInt.compareTo(BigInteger.ZERO) < 0) { + return BvUtils.bigIntegerToBvLitExpr(thisAbs.mod(thatAbs).negate(), getType().getSize(), getType().isSigned()); + } else if (thisInt.compareTo(BigInteger.ZERO) < 0 && thatInt.compareTo(BigInteger.ZERO) >= 0) { + BigInteger result = thisAbs.mod(thatAbs); + if (result.compareTo(BigInteger.ZERO) != 0) { + result = thatAbs.subtract(result); + } + return BvUtils.bigIntegerToBvLitExpr(result, getType().getSize(), getType().isSigned()); + } else { + return BvUtils.bigIntegerToBvLitExpr(thisInt.mod(thatInt), getType().getSize(), getType().isSigned()); + } + } + public BoolLitExpr eq(final BvLitExpr that) { checkArgument(this.getType().equals(that.getType())); return Bool(Arrays.equals(this.getValue(), that.getValue())); diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvModExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvModExpr.java new file mode 100644 index 0000000000..c23218d7bf --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvModExpr.java @@ -0,0 +1,81 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.BinaryExpr; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.abstracttype.ModExpr; + +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class BvModExpr extends ModExpr { + + private static final int HASH_SEED = 1451; + private static final String OPERATOR_LABEL = "mod"; + + private BvModExpr(final Expr leftOp, final Expr rightOp) { + super(leftOp, rightOp); + } + + public static BvModExpr of(final Expr leftOp, final Expr rightOp) { + return new BvModExpr(leftOp, rightOp); + } + + public static BvModExpr create(final Expr leftOp, final Expr rightOp) { + final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); + final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + return BvModExpr.of(newLeftOp, newRightOp); + } + + @Override + public BvType getType() { + return getOps().get(0).getType(); + } + + @Override + public BvLitExpr eval(final Valuation val) { + final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); + final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); + return leftOpVal.mod(rightOpVal); + } + + @Override + public BvModExpr with(final Expr leftOp, final Expr rightOp) { + if (leftOp == getLeftOp() && rightOp == getRightOp()) { + return this; + } else { + return BvModExpr.of(leftOp, rightOp); + } + } + + @Override + public BvModExpr withLeftOp(final Expr leftOp) { + return with(leftOp, getRightOp()); + } + + @Override + public BvModExpr withRightOp(final Expr rightOp) { + return with(getLeftOp(), rightOp); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvModExpr) { + final BvModExpr that = (BvModExpr) obj; + return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvRemExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvRemExpr.java new file mode 100644 index 0000000000..9fe45006d3 --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvRemExpr.java @@ -0,0 +1,82 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.BinaryExpr; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.abstracttype.RemExpr; + +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class BvRemExpr extends RemExpr { + + private static final int HASH_SEED = 985; + + private static final String OPERATOR_LABEL = "rem"; + + private BvRemExpr(final Expr leftOp, final Expr rightOp) { + super(leftOp, rightOp); + } + + public static BvRemExpr of(final Expr leftOp, final Expr rightOp) { + return new BvRemExpr(leftOp, rightOp); + } + + public static BvRemExpr create(final Expr leftOp, final Expr rightOp) { + final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); + final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + return BvRemExpr.of(newLeftOp, newRightOp); + } + + @Override + public BvType getType() { + return getOps().get(0).getType(); + } + + @Override + public BvLitExpr eval(final Valuation val) { + final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); + final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); + return leftOpVal.rem(rightOpVal); + } + + @Override + public BvRemExpr with(final Expr leftOp, final Expr rightOp) { + if (leftOp == getLeftOp() && rightOp == getRightOp()) { + return this; + } else { + return BvRemExpr.of(leftOp, rightOp); + } + } + + @Override + public BvRemExpr withLeftOp(final Expr leftOp) { + return with(leftOp, getRightOp()); + } + + @Override + public BvRemExpr withRightOp(final Expr rightOp) { + return with(getLeftOp(), rightOp); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvRemExpr) { + final BvRemExpr that = (BvRemExpr) obj; + return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java index 48c3e2698e..ff6f24bd14 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java @@ -6,7 +6,7 @@ import static com.google.common.base.Preconditions.checkArgument; -public final class BvType implements Additive, Multiplicative, Equational, Ordered { +public final class BvType implements Additive, Multiplicative, Divisible, Equational, Ordered { private final static int HASH_SEED = 5674; private final static String TYPE_LABEL = "Bv"; @@ -58,6 +58,17 @@ public BvDivExpr Div(final Expr leftOp, final Expr rightOp) { return BvExprs.Div(leftOp, rightOp); } + + @Override + public ModExpr Mod(Expr leftOp, Expr rightOp) { + return BvExprs.Mod(leftOp, rightOp); + } + + @Override + public RemExpr Rem(Expr leftOp, Expr rightOp) { + return BvExprs.Rem(leftOp, rightOp); + } + @Override public EqExpr Eq(Expr leftOp, Expr rightOp) { return BvEqExpr.of(leftOp, rightOp); diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntExprs.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntExprs.java index 2aa1317b86..fdf90473d2 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntExprs.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntExprs.java @@ -56,12 +56,12 @@ public static IntDivExpr Div(final Expr leftOp, final Expr rig return IntDivExpr.of(leftOp, rightOp); } - public static ModExpr Mod(final Expr leftOp, final Expr rightOp) { - return ModExpr.of(leftOp, rightOp); + public static IntModExpr Mod(final Expr leftOp, final Expr rightOp) { + return IntModExpr.of(leftOp, rightOp); } - public static RemExpr Rem(final Expr leftOp, final Expr rightOp) { - return RemExpr.of(leftOp, rightOp); + public static IntRemExpr Rem(final Expr leftOp, final Expr rightOp) { + return IntRemExpr.of(leftOp, rightOp); } public static IntEqExpr Eq(final Expr leftOp, final Expr rightOp) { diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/ModExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntModExpr.java similarity index 72% rename from subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/ModExpr.java rename to subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntModExpr.java index 9f3def0584..094238595e 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/ModExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntModExpr.java @@ -21,24 +21,25 @@ import hu.bme.mit.theta.core.model.Valuation; import hu.bme.mit.theta.core.type.BinaryExpr; import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.abstracttype.ModExpr; -public final class ModExpr extends BinaryExpr { +public final class IntModExpr extends ModExpr { private static final int HASH_SEED = 109; private static final String OPERATOR_LABEL = "mod"; - private ModExpr(final Expr leftOp, final Expr rightOp) { + private IntModExpr(final Expr leftOp, final Expr rightOp) { super(leftOp, rightOp); } - public static ModExpr of(final Expr leftOp, final Expr rightOp) { - return new ModExpr(leftOp, rightOp); + public static IntModExpr of(final Expr leftOp, final Expr rightOp) { + return new IntModExpr(leftOp, rightOp); } - public static ModExpr create(final Expr leftOp, final Expr rightOp) { + public static IntModExpr create(final Expr leftOp, final Expr rightOp) { final Expr newLeftOp = cast(leftOp, Int()); final Expr newRightOp = cast(rightOp, Int()); - return ModExpr.of(newLeftOp, newRightOp); + return IntModExpr.of(newLeftOp, newRightOp); } @Override @@ -54,21 +55,21 @@ public IntLitExpr eval(final Valuation val) { } @Override - public ModExpr with(final Expr leftOp, final Expr rightOp) { + public IntModExpr with(final Expr leftOp, final Expr rightOp) { if (leftOp == getLeftOp() && rightOp == getRightOp()) { return this; } else { - return ModExpr.of(leftOp, rightOp); + return IntModExpr.of(leftOp, rightOp); } } @Override - public ModExpr withLeftOp(final Expr leftOp) { + public IntModExpr withLeftOp(final Expr leftOp) { return with(leftOp, getRightOp()); } @Override - public ModExpr withRightOp(final Expr rightOp) { + public IntModExpr withRightOp(final Expr rightOp) { return with(getLeftOp(), rightOp); } @@ -76,8 +77,8 @@ public ModExpr withRightOp(final Expr rightOp) { public boolean equals(final Object obj) { if (this == obj) { return true; - } else if (obj instanceof ModExpr) { - final ModExpr that = (ModExpr) obj; + } else if (obj instanceof IntModExpr) { + final IntModExpr that = (IntModExpr) obj; return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); } else { return false; diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/RemExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntRemExpr.java similarity index 72% rename from subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/RemExpr.java rename to subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntRemExpr.java index ee41964e46..c8753d0981 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/RemExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntRemExpr.java @@ -21,25 +21,26 @@ import hu.bme.mit.theta.core.model.Valuation; import hu.bme.mit.theta.core.type.BinaryExpr; import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.abstracttype.RemExpr; -public final class RemExpr extends BinaryExpr { +public final class IntRemExpr extends RemExpr { private static final int HASH_SEED = 199; private static final String OPERATOR_LABEL = "rem"; - private RemExpr(final Expr leftOp, final Expr rightOp) { + private IntRemExpr(final Expr leftOp, final Expr rightOp) { super(leftOp, rightOp); } - public static RemExpr of(final Expr leftOp, final Expr rightOp) { - return new RemExpr(leftOp, rightOp); + public static IntRemExpr of(final Expr leftOp, final Expr rightOp) { + return new IntRemExpr(leftOp, rightOp); } - public static RemExpr create(final Expr leftOp, final Expr rightOp) { + public static IntRemExpr create(final Expr leftOp, final Expr rightOp) { final Expr newLeftOp = cast(leftOp, Int()); final Expr newRightOp = cast(rightOp, Int()); - return RemExpr.of(newLeftOp, newRightOp); + return IntRemExpr.of(newLeftOp, newRightOp); } @Override @@ -55,21 +56,21 @@ public IntLitExpr eval(final Valuation val) { } @Override - public RemExpr with(final Expr leftOp, final Expr rightOp) { + public IntRemExpr with(final Expr leftOp, final Expr rightOp) { if (leftOp == getLeftOp() && rightOp == getRightOp()) { return this; } else { - return RemExpr.of(leftOp, rightOp); + return IntRemExpr.of(leftOp, rightOp); } } @Override - public RemExpr withLeftOp(final Expr leftOp) { + public IntRemExpr withLeftOp(final Expr leftOp) { return with(leftOp, getRightOp()); } @Override - public RemExpr withRightOp(final Expr rightOp) { + public IntRemExpr withRightOp(final Expr rightOp) { return with(getLeftOp(), rightOp); } @@ -77,8 +78,8 @@ public RemExpr withRightOp(final Expr rightOp) { public boolean equals(final Object obj) { if (this == obj) { return true; - } else if (obj instanceof RemExpr) { - final RemExpr that = (RemExpr) obj; + } else if (obj instanceof IntRemExpr) { + final IntRemExpr that = (IntRemExpr) obj; return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); } else { return false; diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntType.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntType.java index cae262857c..9a4744c44c 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntType.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntType.java @@ -17,14 +17,10 @@ import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.Type; -import hu.bme.mit.theta.core.type.abstracttype.Additive; -import hu.bme.mit.theta.core.type.abstracttype.Castable; -import hu.bme.mit.theta.core.type.abstracttype.Equational; -import hu.bme.mit.theta.core.type.abstracttype.Multiplicative; -import hu.bme.mit.theta.core.type.abstracttype.Ordered; +import hu.bme.mit.theta.core.type.abstracttype.*; import hu.bme.mit.theta.core.type.rattype.RatType; -public final class IntType implements Additive, Multiplicative, Equational, Ordered, +public final class IntType implements Additive, Multiplicative, Divisible, Equational, Ordered, Castable { private static final IntType INSTANCE = new IntType(); @@ -80,6 +76,16 @@ public IntDivExpr Div(final Expr leftOp, final Expr rightOp) { return IntExprs.Div(leftOp, rightOp); } + @Override + public ModExpr Mod(Expr leftOp, Expr rightOp) { + return IntExprs.Mod(leftOp, rightOp); + } + + @Override + public RemExpr Rem(Expr leftOp, Expr rightOp) { + return IntExprs.Rem(leftOp, rightOp); + } + @Override public IntEqExpr Eq(final Expr leftOp, final Expr rightOp) { return IntExprs.Eq(leftOp, rightOp); @@ -119,5 +125,4 @@ public Expr Cast(final Expr op, f throw new ClassCastException("Int cannot be cast to " + type); } } - } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java index dbb685e0c6..c3fb57fc4b 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java @@ -59,7 +59,7 @@ import hu.bme.mit.theta.core.type.inttype.IntSubExpr; import hu.bme.mit.theta.core.type.inttype.IntToRatExpr; import hu.bme.mit.theta.core.type.inttype.IntType; -import hu.bme.mit.theta.core.type.inttype.ModExpr; +import hu.bme.mit.theta.core.type.inttype.IntModExpr; import hu.bme.mit.theta.core.type.rattype.RatAddExpr; import hu.bme.mit.theta.core.type.rattype.RatDivExpr; import hu.bme.mit.theta.core.type.rattype.RatEqExpr; @@ -130,7 +130,7 @@ public final class ExprSimplifier { .addCase(IntDivExpr.class, ExprSimplifier::simplifyIntDiv) - .addCase(ModExpr.class, ExprSimplifier::simplifyMod) + .addCase(IntModExpr.class, ExprSimplifier::simplifyMod) .addCase(IntEqExpr.class, ExprSimplifier::simplifyIntEq) @@ -746,7 +746,7 @@ private static Expr simplifyIntDiv(final IntDivExpr expr, final Valuati return expr.with(leftOp, rightOp); } - private static Expr simplifyMod(final ModExpr expr, final Valuation val) { + private static Expr simplifyMod(final IntModExpr expr, final Valuation val) { final Expr leftOp = simplify(expr.getLeftOp(), val); final Expr rightOp = simplify(expr.getRightOp(), val); diff --git a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java index 62ad8ee587..a11a553bdd 100644 --- a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java +++ b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java @@ -15,7 +15,6 @@ */ package hu.bme.mit.theta.solver.z3; -import java.math.BigInteger; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.stream.Stream; @@ -23,7 +22,6 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.ImmutableList; -import com.microsoft.z3.BitVecExpr; import com.microsoft.z3.Context; import hu.bme.mit.theta.common.DispatchTable; @@ -67,8 +65,8 @@ import hu.bme.mit.theta.core.type.inttype.IntNeqExpr; import hu.bme.mit.theta.core.type.inttype.IntSubExpr; import hu.bme.mit.theta.core.type.inttype.IntToRatExpr; -import hu.bme.mit.theta.core.type.inttype.ModExpr; -import hu.bme.mit.theta.core.type.inttype.RemExpr; +import hu.bme.mit.theta.core.type.inttype.IntModExpr; +import hu.bme.mit.theta.core.type.inttype.IntRemExpr; import hu.bme.mit.theta.core.type.rattype.RatAddExpr; import hu.bme.mit.theta.core.type.rattype.RatDivExpr; import hu.bme.mit.theta.core.type.rattype.RatEqExpr; @@ -171,9 +169,9 @@ public Z3ExprTransformer(final Z3TransformationManager transformer, final Contex .addCase(IntDivExpr.class, this::transformIntDiv) - .addCase(ModExpr.class, this::transformMod) + .addCase(IntModExpr.class, this::transformIntMod) - .addCase(RemExpr.class, this::transformRem) + .addCase(IntRemExpr.class, this::transformIntRem) .addCase(IntEqExpr.class, this::transformIntEq) @@ -203,6 +201,10 @@ public Z3ExprTransformer(final Z3TransformationManager transformer, final Contex .addCase(BvDivExpr.class, this::transformBvDiv) + .addCase(BvModExpr.class, this::transformBvMod) + + .addCase(BvRemExpr.class, this::transformBvRem) + .addCase(BvEqExpr.class, this::transformBvEq) .addCase(BvNeqExpr.class, this::transformBvNeq) @@ -464,13 +466,13 @@ private com.microsoft.z3.Expr transformIntDiv(final IntDivExpr expr) { return context.mkDiv(leftOpTerm, rightOpTerm); } - private com.microsoft.z3.Expr transformMod(final ModExpr expr) { + private com.microsoft.z3.Expr transformIntMod(final IntModExpr expr) { final com.microsoft.z3.IntExpr leftOpTerm = (com.microsoft.z3.IntExpr) toTerm(expr.getLeftOp()); final com.microsoft.z3.IntExpr rightOpTerm = (com.microsoft.z3.IntExpr) toTerm(expr.getRightOp()); return context.mkMod(leftOpTerm, rightOpTerm); } - private com.microsoft.z3.Expr transformRem(final RemExpr expr) { + private com.microsoft.z3.Expr transformIntRem(final IntRemExpr expr) { final com.microsoft.z3.IntExpr leftOpTerm = (com.microsoft.z3.IntExpr) toTerm(expr.getLeftOp()); final com.microsoft.z3.IntExpr rightOpTerm = (com.microsoft.z3.IntExpr) toTerm(expr.getRightOp()); return context.mkRem(leftOpTerm, rightOpTerm); @@ -574,6 +576,30 @@ private com.microsoft.z3.Expr transformBvDiv(final BvDivExpr expr) { } } + private com.microsoft.z3.Expr transformBvMod(final BvModExpr expr) { + final com.microsoft.z3.BitVecExpr leftOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getLeftOp()); + final com.microsoft.z3.BitVecExpr rightOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getRightOp()); + + if(expr.getType().isSigned()) { + return context.mkBVSMod(leftOpTerm, rightOpTerm); + } + else { + return context.mkBVURem(leftOpTerm, rightOpTerm); + } + } + + private com.microsoft.z3.Expr transformBvRem(final BvRemExpr expr) { + final com.microsoft.z3.BitVecExpr leftOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getLeftOp()); + final com.microsoft.z3.BitVecExpr rightOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getRightOp()); + + if(expr.getType().isSigned()) { + return context.mkBVSRem(leftOpTerm, rightOpTerm); + } + else { + return context.mkBVURem(leftOpTerm, rightOpTerm); + } + } + private com.microsoft.z3.Expr transformBvGeq(final BvGeqExpr expr) { final com.microsoft.z3.BitVecExpr leftOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getLeftOp()); final com.microsoft.z3.BitVecExpr rightOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getRightOp()); diff --git a/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java b/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java index 7739311e3b..70074cb41f 100644 --- a/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java +++ b/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java @@ -264,4 +264,26 @@ public void testBV7() { solver.pop(); } + @Test + public void testBV8() { + final Solver solver = Z3SolverFactory.getInstace().createSolver(); + + final ConstDecl cx = Const("x", BvType(4, false)); + final ConstDecl cy = Const("y", BvType(4, false)); + + solver.push(); + + solver.add(BvExprs.Eq(cx.getRef(), Bv(new boolean[] {true, false, true, false}, false))); + solver.add(BvExprs.Eq(cy.getRef(), BvExprs.Mod(cx.getRef(), Bv(new boolean[] {false, true, false, false}, false)))); + + SolverStatus status = solver.check(); + assertTrue(status.isSat()); + + Valuation model = solver.getModel(); + assertNotNull(model); + assertNotNull(model.toMap()); + + solver.pop(); + } + } diff --git a/subprojects/sts/src/main/java/hu/bme/mit/theta/sts/dsl/StsExprCreatorVisitor.java b/subprojects/sts/src/main/java/hu/bme/mit/theta/sts/dsl/StsExprCreatorVisitor.java index f7ed5bdf7b..805f3232c7 100644 --- a/subprojects/sts/src/main/java/hu/bme/mit/theta/sts/dsl/StsExprCreatorVisitor.java +++ b/subprojects/sts/src/main/java/hu/bme/mit/theta/sts/dsl/StsExprCreatorVisitor.java @@ -77,8 +77,8 @@ import hu.bme.mit.theta.core.type.booltype.TrueExpr; import hu.bme.mit.theta.core.type.inttype.IntLitExpr; import hu.bme.mit.theta.core.type.inttype.IntType; -import hu.bme.mit.theta.core.type.inttype.ModExpr; -import hu.bme.mit.theta.core.type.inttype.RemExpr; +import hu.bme.mit.theta.core.type.inttype.IntModExpr; +import hu.bme.mit.theta.core.type.inttype.IntRemExpr; import hu.bme.mit.theta.core.type.rattype.RatLitExpr; import hu.bme.mit.theta.core.utils.TypeUtils; import hu.bme.mit.theta.sts.dsl.gen.StsDslBaseVisitor; @@ -430,13 +430,13 @@ private DivExpr createDivExpr(final Expr leftOp, final Expr rightOp) { return Div(leftOp, rightOp); } - private ModExpr createModExpr(final Expr uncastLeftOp, final Expr uncastRightOp) { + private IntModExpr createModExpr(final Expr uncastLeftOp, final Expr uncastRightOp) { final Expr leftOp = TypeUtils.cast(uncastLeftOp, Int()); final Expr rightOp = TypeUtils.cast(uncastRightOp, Int()); return Mod(leftOp, rightOp); } - private RemExpr createRemExpr(final Expr uncastLeftOp, final Expr uncastRightOp) { + private IntRemExpr createRemExpr(final Expr uncastLeftOp, final Expr uncastRightOp) { final Expr leftOp = TypeUtils.cast(uncastLeftOp, Int()); final Expr rightOp = TypeUtils.cast(uncastRightOp, Int()); return Rem(leftOp, rightOp); diff --git a/subprojects/xta/src/main/java/hu/bme/mit/theta/xta/dsl/XtaExpression.java b/subprojects/xta/src/main/java/hu/bme/mit/theta/xta/dsl/XtaExpression.java index f58b617f4e..464bed9b89 100644 --- a/subprojects/xta/src/main/java/hu/bme/mit/theta/xta/dsl/XtaExpression.java +++ b/subprojects/xta/src/main/java/hu/bme/mit/theta/xta/dsl/XtaExpression.java @@ -32,7 +32,7 @@ import hu.bme.mit.theta.core.type.booltype.BoolType; import hu.bme.mit.theta.core.type.inttype.IntLitExpr; import hu.bme.mit.theta.core.type.inttype.IntType; -import hu.bme.mit.theta.core.type.inttype.ModExpr; +import hu.bme.mit.theta.core.type.inttype.IntModExpr; import hu.bme.mit.theta.core.type.rattype.RatLitExpr; import hu.bme.mit.theta.core.utils.ExprUtils; import hu.bme.mit.theta.core.utils.TypeUtils; @@ -268,7 +268,7 @@ private DivExpr createDivExpr(final Expr uncastLeftOp, final Expr uncas return Div(leftOp, rightOp); } - private ModExpr createModExpr(final Expr uncastLeftOp, final Expr uncastRightOp) { + private IntModExpr createModExpr(final Expr uncastLeftOp, final Expr uncastRightOp) { final Expr leftOp = TypeUtils.cast(uncastLeftOp, Int()); final Expr rightOp = TypeUtils.cast(uncastRightOp, Int()); return Mod(leftOp, rightOp); From 43fb8fdaaed8489a97f77fd3ddae6b4cd2b56afb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Dobos-Kov=C3=A1cs?= Date: Thu, 2 Apr 2020 13:05:59 +0200 Subject: [PATCH 08/23] Basic bitvector support: bitwise operations --- subprojects/cfa/src/main/antlr/CfaDsl.g4 | 49 +++++++++- .../bme/mit/theta/cfa/dsl/CfaExpression.java | 89 +++++++++++++++++++ .../mit/theta/cfa/dsl/CfaDslManagerTest.java | 5 +- subprojects/cfa/src/test/resources/bv2.cfa | 17 ++++ .../mit/theta/core/type/bvtype/BvAndExpr.java | 79 ++++++++++++++++ .../mit/theta/core/type/bvtype/BvExprs.java | 24 +++++ .../mit/theta/core/type/bvtype/BvLitExpr.java | 41 +++++++++ .../mit/theta/core/type/bvtype/BvNotExpr.java | 69 ++++++++++++++ .../mit/theta/core/type/bvtype/BvOrExpr.java | 80 +++++++++++++++++ .../core/type/bvtype/BvShiftLeftExpr.java | 79 ++++++++++++++++ .../core/type/bvtype/BvShiftRightExpr.java | 79 ++++++++++++++++ .../mit/theta/core/type/bvtype/BvXorExpr.java | 79 ++++++++++++++++ .../bme/mit/theta/core/utils/TypeUtils.java | 12 +++ .../theta/solver/z3/Z3ExprTransformer.java | 57 ++++++++++++ .../bme/mit/theta/solver/z3/Z3SolverTest.java | 88 ++++++++++++++++++ 15 files changed, 843 insertions(+), 4 deletions(-) create mode 100644 subprojects/cfa/src/test/resources/bv2.cfa create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAndExpr.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNotExpr.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvOrExpr.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvShiftLeftExpr.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvShiftRightExpr.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvXorExpr.java diff --git a/subprojects/cfa/src/main/antlr/CfaDsl.g4 b/subprojects/cfa/src/main/antlr/CfaDsl.g4 index d41feace78..4da5278546 100644 --- a/subprojects/cfa/src/main/antlr/CfaDsl.g4 +++ b/subprojects/cfa/src/main/antlr/CfaDsl.g4 @@ -203,9 +203,25 @@ equalityExpr ; relationExpr - : leftOp=additiveExpr (oper=(LT | LEQ | GT | GEQ) rightOp=additiveExpr)? + : leftOp=bitwiseOrExpr (oper=(LT | LEQ | GT | GEQ) rightOp=bitwiseOrExpr)? ; +bitwiseOrExpr + : leftOp=bitwiseXorExpr (oper=BITWISE_OR rightOp=bitwiseXorExpr)? + ; + +bitwiseXorExpr + : leftOp=bitwiseAndExpr (oper=BITWISE_XOR rightOp=bitwiseAndExpr)? + ; + +bitwiseAndExpr + : leftOp=bitwiseShiftExpr (oper=BITWISE_AND rightOp=bitwiseShiftExpr)? + ; + +bitwiseShiftExpr + : leftOp=additiveExpr (oper=(BITWISE_SHIFT_LEFT | BITWISE_SHIFT_RIGHT) rightOp=additiveExpr)? + ; + additiveExpr : ops+=multiplicativeExpr (opers+=(PLUS | MINUS) ops+=multiplicativeExpr)* ; @@ -215,10 +231,15 @@ multiplicativeExpr ; negExpr - : accessorExpr + : bitwiseNotExpr | MINUS op=negExpr ; +bitwiseNotExpr + : accessorExpr + | BITWISE_NOT op=bitwiseNotExpr + ; + accessorExpr : op=primaryExpr (accesses+=access)* ; @@ -360,6 +381,30 @@ PERCENT : '%' ; +BITWISE_OR + : '|' + ; + +BITWISE_XOR + : '^' + ; + +BITWISE_AND + : '&' + ; + +BITWISE_SHIFT_LEFT + : LT LT + ; + +BITWISE_SHIFT_RIGHT + : GT GT + ; + +BITWISE_NOT + : '~' + ; + TRUE: 'true' ; diff --git a/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java b/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java index 723420740c..2c5805c833 100644 --- a/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java +++ b/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java @@ -41,6 +41,7 @@ import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; import static hu.bme.mit.theta.core.type.rattype.RatExprs.Rat; import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.castBv; import static java.util.stream.Collectors.toList; import java.math.BigInteger; @@ -50,6 +51,8 @@ import java.util.stream.Stream; import hu.bme.mit.theta.core.type.abstracttype.*; +import hu.bme.mit.theta.core.type.bvtype.BvExprs; +import hu.bme.mit.theta.core.type.bvtype.BvType; import org.antlr.v4.runtime.Token; import com.google.common.collect.ImmutableList; @@ -332,6 +335,82 @@ public Expr visitRelationExpr(final RelationExprContext ctx) { //// + @Override + public Expr visitBitwiseOrExpr(final BitwiseOrExprContext ctx) { + if (ctx.rightOp != null) { + final Expr leftOp = castBv(ctx.leftOp.accept(this)); + final Expr rightOp = castBv(ctx.rightOp.accept(this)); + + switch (ctx.oper.getType()) { + case BITWISE_OR: + return BvExprs.Or(leftOp, rightOp); + default: + throw new AssertionError(); + } + + } else { + return visitChildren(ctx); + } + } + + @Override + public Expr visitBitwiseXorExpr(final BitwiseXorExprContext ctx) { + if (ctx.rightOp != null) { + final Expr leftOp = castBv(ctx.leftOp.accept(this)); + final Expr rightOp = castBv(ctx.rightOp.accept(this)); + + switch (ctx.oper.getType()) { + case BITWISE_XOR: + return BvExprs.Xor(leftOp, rightOp); + default: + throw new AssertionError(); + } + + } else { + return visitChildren(ctx); + } + } + + @Override + public Expr visitBitwiseAndExpr(final BitwiseAndExprContext ctx) { + if (ctx.rightOp != null) { + final Expr leftOp = castBv(ctx.leftOp.accept(this)); + final Expr rightOp = castBv(ctx.rightOp.accept(this)); + + switch (ctx.oper.getType()) { + case BITWISE_AND: + return BvExprs.And(leftOp, rightOp); + default: + throw new AssertionError(); + } + + } else { + return visitChildren(ctx); + } + } + + @Override + public Expr visitBitwiseShiftExpr(final BitwiseShiftExprContext ctx) { + if (ctx.rightOp != null) { + final Expr leftOp = castBv(ctx.leftOp.accept(this)); + final Expr rightOp = castBv(ctx.rightOp.accept(this)); + + switch (ctx.oper.getType()) { + case BITWISE_SHIFT_LEFT: + return BvExprs.ShiftLeft(leftOp, rightOp); + case BITWISE_SHIFT_RIGHT: + return BvExprs.ShiftRight(leftOp, rightOp); + default: + throw new AssertionError(); + } + + } else { + return visitChildren(ctx); + } + } + + //// + @Override public Expr visitAdditiveExpr(final AdditiveExprContext ctx) { if (ctx.ops.size() > 1) { @@ -487,6 +566,16 @@ public Expr visitNegExpr(final NegExprContext ctx) { } } + @Override + public Expr visitBitwiseNotExpr(final BitwiseNotExprContext ctx) { + if (ctx.op != null) { + final Expr op = castBv(ctx.op.accept(this)); + return BvExprs.Not(op); + } else { + return visitChildren(ctx); + } + } + //// @Override diff --git a/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java b/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java index 891d22bce1..07913dad47 100644 --- a/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java +++ b/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java @@ -58,13 +58,14 @@ public static Collection data() { {"/counter5_true.cfa", 1, 6, 6, 6}, - {"/bv.cfa", 1, 6, 6, 6} + //{"/bv.cfa", 1, 6, 6, 6} + + {"/bv2.cfa", 1, 6, 6, 6} }); } @Test - @Ignore public void test() throws FileNotFoundException, IOException, InterruptedException { final InputStream inputStream = getClass().getResourceAsStream(filepath); final CFA cfa = CfaDslManager.createCfa(inputStream); diff --git a/subprojects/cfa/src/test/resources/bv2.cfa b/subprojects/cfa/src/test/resources/bv2.cfa new file mode 100644 index 0000000000..16625cc7a7 --- /dev/null +++ b/subprojects/cfa/src/test/resources/bv2.cfa @@ -0,0 +1,17 @@ +main process cfa { + var x : bv[4] + + init loc L0 + loc L1 + loc L2 + loc L3 + final loc END + error loc ERR + + L0 -> L1 { x := 4'b0001 } + L1 -> L2 { assume (x | 4'b0100) /= 4'b0100 } + L1 -> L3 { assume not ((x | 4'b0100) /= 4'b0100) } + L2 -> L1 { x := x * 4'd2 } + L3 -> END { assume (x & 4'b0100) /= 4'b0100 } + L3 -> ERR { assume not ((x & 4'b0100) /= 4'b0100) } +} \ No newline at end of file diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAndExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAndExpr.java new file mode 100644 index 0000000000..17c7fa1752 --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAndExpr.java @@ -0,0 +1,79 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.BinaryExpr; +import hu.bme.mit.theta.core.type.Expr; + +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class BvAndExpr extends BinaryExpr { + private static final int HASH_SEED = 9125; + private static final String OPERATOR_LABEL = "&"; + + private BvAndExpr(final Expr leftOp, final Expr rightOp) { + super(leftOp, rightOp); + } + + public static BvAndExpr of(final Expr leftOp, final Expr rightOp) { + return new BvAndExpr(leftOp, rightOp); + } + + public static BvAndExpr create(final Expr leftOp, final Expr rightOp) { + final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); + final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + return BvAndExpr.of(newLeftOp, newRightOp); + } + + @Override + public BvType getType() { + return getOps().get(0).getType(); + } + + @Override + public BvLitExpr eval(final Valuation val) { + final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); + final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); + return leftOpVal.and(rightOpVal); + } + + @Override + public BvAndExpr with(final Expr leftOp, final Expr rightOp) { + if (leftOp == getLeftOp() && rightOp == getRightOp()) { + return this; + } else { + return BvAndExpr.of(leftOp, rightOp); + } + } + + @Override + public BvAndExpr withLeftOp(final Expr leftOp) { + return with(leftOp, getRightOp()); + } + + @Override + public BvAndExpr withRightOp(final Expr rightOp) { + return with(getLeftOp(), rightOp); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvAndExpr) { + final BvAndExpr that = (BvAndExpr) obj; + return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java index fbb495abb6..aa664e2623 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java @@ -49,6 +49,30 @@ public static BvRemExpr Rem(final Expr leftOp, final Expr rightO return BvRemExpr.of(leftOp, rightOp); } + public static BvOrExpr Or(final Expr leftOp, final Expr rightOp) { + return BvOrExpr.of(leftOp, rightOp); + } + + public static BvAndExpr And(final Expr leftOp, final Expr rightOp) { + return BvAndExpr.of(leftOp, rightOp); + } + + public static BvXorExpr Xor(final Expr leftOp, final Expr rightOp) { + return BvXorExpr.of(leftOp, rightOp); + } + + public static BvNotExpr Not(final Expr op) { + return BvNotExpr.of(op); + } + + public static BvShiftLeftExpr ShiftLeft(final Expr leftOp, final Expr rightOp) { + return BvShiftLeftExpr.of(leftOp, rightOp); + } + + public static BvShiftRightExpr ShiftRight(final Expr leftOp, final Expr rightOp) { + return BvShiftRightExpr.of(leftOp, rightOp); + } + public static BvEqExpr Eq(final Expr leftOp, final Expr rightOp) { return BvEqExpr.of(leftOp, rightOp); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java index 98df65c024..52ef58c1c9 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java @@ -86,6 +86,47 @@ public BvLitExpr div(final BvLitExpr that) { return BvUtils.bigIntegerToBvLitExpr(div, getType().getSize(), getType().isSigned()); } + public BvLitExpr and(final BvLitExpr that) { + checkArgument(this.getType().equals(that.getType())); + BigInteger and = BvUtils.bvLitExprToBigInteger(this).and(BvUtils.bvLitExprToBigInteger(that)); + return BvUtils.bigIntegerToBvLitExpr(and, getType().getSize(), getType().isSigned()); + } + + public BvLitExpr or(final BvLitExpr that) { + checkArgument(this.getType().equals(that.getType())); + BigInteger or = BvUtils.bvLitExprToBigInteger(this).or(BvUtils.bvLitExprToBigInteger(that)); + return BvUtils.bigIntegerToBvLitExpr(or, getType().getSize(), getType().isSigned()); + } + + public BvLitExpr xor(final BvLitExpr that) { + checkArgument(this.getType().equals(that.getType())); + BigInteger xor = BvUtils.bvLitExprToBigInteger(this).xor(BvUtils.bvLitExprToBigInteger(that)); + return BvUtils.bigIntegerToBvLitExpr(xor, getType().getSize(), getType().isSigned()); + } + + public BvLitExpr not() { + BigInteger not = BvUtils.bvLitExprToBigInteger(this).not(); + return BvUtils.bigIntegerToBvLitExpr(not, getType().getSize(), getType().isSigned()); + } + + public BvLitExpr shiftLeft(final BvLitExpr that) { + checkArgument(this.getType().equals(that.getType())); + BigInteger shift = BvUtils.bvLitExprToBigInteger(this); + for(BigInteger i = BigInteger.ZERO; i.compareTo(BvUtils.bvLitExprToBigInteger(that)) < 0; i = i.add(BigInteger.ONE)) { + shift = shift.multiply(BigInteger.TWO); + } + return BvUtils.bigIntegerToBvLitExpr(shift, getType().getSize(), getType().isSigned()); + } + + public BvLitExpr shiftRight(final BvLitExpr that) { + checkArgument(this.getType().equals(that.getType())); + BigInteger shift = BvUtils.bvLitExprToBigInteger(this); + for(BigInteger i = BigInteger.ZERO; i.compareTo(BvUtils.bvLitExprToBigInteger(that)) < 0; i = i.add(BigInteger.ONE)) { + shift = shift.multiply(BigInteger.TWO); + } + return BvUtils.bigIntegerToBvLitExpr(shift, getType().getSize(), getType().isSigned()); + } + public BvLitExpr mod(final BvLitExpr that) { checkArgument(this.getType().equals(that.getType())); // Always positive semantics: diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNotExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNotExpr.java new file mode 100644 index 0000000000..0f26a7ff99 --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNotExpr.java @@ -0,0 +1,69 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.abstracttype.NegExpr; + +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class BvNotExpr extends NegExpr { + + private static final int HASH_SEED = 1527; + private static final String OPERATOR_LABEL = "~"; + + private BvNotExpr(final Expr op) { + super(op); + } + + public static BvNotExpr of(final Expr op) { + return new BvNotExpr(op); + } + + public static BvNotExpr create(final Expr op) { + final Expr newOp = cast(op, (BvType) op.getType()); + return BvNotExpr.of(newOp); + } + + @Override + public BvType getType() { + return getOp().getType(); + } + + @Override + public BvLitExpr eval(final Valuation val) { + final BvLitExpr opVal = (BvLitExpr) getOp().eval(val); + return opVal.not(); + } + + @Override + public BvNotExpr with(final Expr op) { + if (op == getOp()) { + return this; + } else { + return BvNotExpr.of(op); + } + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvNotExpr) { + final BvNotExpr that = (BvNotExpr) obj; + return this.getOp().equals(that.getOp()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } + +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvOrExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvOrExpr.java new file mode 100644 index 0000000000..882394281e --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvOrExpr.java @@ -0,0 +1,80 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.BinaryExpr; +import hu.bme.mit.theta.core.type.Expr; + +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class BvOrExpr extends BinaryExpr { + private static final int HASH_SEED = 2745; + private static final String OPERATOR_LABEL = "|"; + + private BvOrExpr(final Expr leftOp, final Expr rightOp) { + super(leftOp, rightOp); + } + + public static BvOrExpr of(final Expr leftOp, final Expr rightOp) { + return new BvOrExpr(leftOp, rightOp); + } + + public static BvOrExpr create(final Expr leftOp, final Expr rightOp) { + final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); + final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + return BvOrExpr.of(newLeftOp, newRightOp); + } + + @Override + public BvType getType() { + return getOps().get(0).getType(); + } + + @Override + public BvLitExpr eval(final Valuation val) { + final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); + final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); + return leftOpVal.or(rightOpVal); + } + + @Override + public BvOrExpr with(final Expr leftOp, final Expr rightOp) { + if (leftOp == getLeftOp() && rightOp == getRightOp()) { + return this; + } else { + return BvOrExpr.of(leftOp, rightOp); + } + } + + @Override + public BvOrExpr withLeftOp(final Expr leftOp) { + return with(leftOp, getRightOp()); + } + + @Override + public BvOrExpr withRightOp(final Expr rightOp) { + return with(getLeftOp(), rightOp); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvOrExpr) { + final BvOrExpr that = (BvOrExpr) obj; + return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } +} + diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvShiftLeftExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvShiftLeftExpr.java new file mode 100644 index 0000000000..36430880b2 --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvShiftLeftExpr.java @@ -0,0 +1,79 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.BinaryExpr; +import hu.bme.mit.theta.core.type.Expr; + +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class BvShiftLeftExpr extends BinaryExpr { + private static final int HASH_SEED = 4288; + private static final String OPERATOR_LABEL = "<<"; + + private BvShiftLeftExpr(final Expr leftOp, final Expr rightOp) { + super(leftOp, rightOp); + } + + public static BvShiftLeftExpr of(final Expr leftOp, final Expr rightOp) { + return new BvShiftLeftExpr(leftOp, rightOp); + } + + public static BvShiftLeftExpr create(final Expr leftOp, final Expr rightOp) { + final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); + final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + return BvShiftLeftExpr.of(newLeftOp, newRightOp); + } + + @Override + public BvType getType() { + return getOps().get(0).getType(); + } + + @Override + public BvLitExpr eval(final Valuation val) { + final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); + final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); + return leftOpVal.shiftLeft(rightOpVal); + } + + @Override + public BvShiftLeftExpr with(final Expr leftOp, final Expr rightOp) { + if (leftOp == getLeftOp() && rightOp == getRightOp()) { + return this; + } else { + return BvShiftLeftExpr.of(leftOp, rightOp); + } + } + + @Override + public BvShiftLeftExpr withLeftOp(final Expr leftOp) { + return with(leftOp, getRightOp()); + } + + @Override + public BvShiftLeftExpr withRightOp(final Expr rightOp) { + return with(getLeftOp(), rightOp); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvShiftLeftExpr) { + final BvShiftLeftExpr that = (BvShiftLeftExpr) obj; + return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvShiftRightExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvShiftRightExpr.java new file mode 100644 index 0000000000..80277fb0cf --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvShiftRightExpr.java @@ -0,0 +1,79 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.BinaryExpr; +import hu.bme.mit.theta.core.type.Expr; + +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class BvShiftRightExpr extends BinaryExpr { + private static final int HASH_SEED = 965; + private static final String OPERATOR_LABEL = ">>"; + + private BvShiftRightExpr(final Expr leftOp, final Expr rightOp) { + super(leftOp, rightOp); + } + + public static BvShiftRightExpr of(final Expr leftOp, final Expr rightOp) { + return new BvShiftRightExpr(leftOp, rightOp); + } + + public static BvShiftRightExpr create(final Expr leftOp, final Expr rightOp) { + final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); + final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + return BvShiftRightExpr.of(newLeftOp, newRightOp); + } + + @Override + public BvType getType() { + return getOps().get(0).getType(); + } + + @Override + public BvLitExpr eval(final Valuation val) { + final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); + final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); + return leftOpVal.shiftRight(rightOpVal); + } + + @Override + public BvShiftRightExpr with(final Expr leftOp, final Expr rightOp) { + if (leftOp == getLeftOp() && rightOp == getRightOp()) { + return this; + } else { + return BvShiftRightExpr.of(leftOp, rightOp); + } + } + + @Override + public BvShiftRightExpr withLeftOp(final Expr leftOp) { + return with(leftOp, getRightOp()); + } + + @Override + public BvShiftRightExpr withRightOp(final Expr rightOp) { + return with(getLeftOp(), rightOp); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvShiftRightExpr) { + final BvShiftRightExpr that = (BvShiftRightExpr) obj; + return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } +} \ No newline at end of file diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvXorExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvXorExpr.java new file mode 100644 index 0000000000..5e5d861bb5 --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvXorExpr.java @@ -0,0 +1,79 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.BinaryExpr; +import hu.bme.mit.theta.core.type.Expr; + +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class BvXorExpr extends BinaryExpr { + private static final int HASH_SEED = 9457; + private static final String OPERATOR_LABEL = "^"; + + private BvXorExpr(final Expr leftOp, final Expr rightOp) { + super(leftOp, rightOp); + } + + public static BvXorExpr of(final Expr leftOp, final Expr rightOp) { + return new BvXorExpr(leftOp, rightOp); + } + + public static BvXorExpr create(final Expr leftOp, final Expr rightOp) { + final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); + final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + return BvXorExpr.of(newLeftOp, newRightOp); + } + + @Override + public BvType getType() { + return getOps().get(0).getType(); + } + + @Override + public BvLitExpr eval(final Valuation val) { + final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); + final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); + return leftOpVal.xor(rightOpVal); + } + + @Override + public BvXorExpr with(final Expr leftOp, final Expr rightOp) { + if (leftOp == getLeftOp() && rightOp == getRightOp()) { + return this; + } else { + return BvXorExpr.of(leftOp, rightOp); + } + } + + @Override + public BvXorExpr withLeftOp(final Expr leftOp) { + return with(leftOp, getRightOp()); + } + + @Override + public BvXorExpr withRightOp(final Expr rightOp) { + return with(getLeftOp(), rightOp); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvXorExpr) { + final BvXorExpr that = (BvXorExpr) obj; + return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/TypeUtils.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/TypeUtils.java index 84b5454ac9..6c13f4338f 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/TypeUtils.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/TypeUtils.java @@ -21,6 +21,7 @@ import hu.bme.mit.theta.core.decl.VarDecl; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.Type; +import hu.bme.mit.theta.core.type.bvtype.BvType; /** * Utility functions related to types. @@ -87,4 +88,15 @@ public static Expr cast(final Expr expr, final T type) { } } + public static Expr castBv(final Expr expr) { + checkNotNull(expr); + + if (expr.getType() instanceof BvType) { + @SuppressWarnings("unchecked") final Expr result = (Expr) expr; + return result; + } else { + throw new ClassCastException("The type of expression " + expr + " is not of type BvType"); + } + } + } diff --git a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java index a11a553bdd..4b760d3f91 100644 --- a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java +++ b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java @@ -205,6 +205,18 @@ public Z3ExprTransformer(final Z3TransformationManager transformer, final Contex .addCase(BvRemExpr.class, this::transformBvRem) + .addCase(BvAndExpr.class, this::transformBvAnd) + + .addCase(BvOrExpr.class, this::transformBvOr) + + .addCase(BvXorExpr.class, this::transformBvXor) + + .addCase(BvNotExpr.class, this::transformBvNot) + + .addCase(BvShiftLeftExpr.class, this::transformBvShiftLeft) + + .addCase(BvShiftRightExpr.class, this::transformBvShiftRight) + .addCase(BvEqExpr.class, this::transformBvEq) .addCase(BvNeqExpr.class, this::transformBvNeq) @@ -600,6 +612,51 @@ private com.microsoft.z3.Expr transformBvRem(final BvRemExpr expr) { } } + private com.microsoft.z3.Expr transformBvAnd(final BvAndExpr expr) { + final com.microsoft.z3.BitVecExpr leftOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getLeftOp()); + final com.microsoft.z3.BitVecExpr rightOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getRightOp()); + + return context.mkBVAND(leftOpTerm, rightOpTerm); + } + + private com.microsoft.z3.Expr transformBvOr(final BvOrExpr expr) { + final com.microsoft.z3.BitVecExpr leftOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getLeftOp()); + final com.microsoft.z3.BitVecExpr rightOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getRightOp()); + + return context.mkBVOR(leftOpTerm, rightOpTerm); + } + + private com.microsoft.z3.Expr transformBvXor(final BvXorExpr expr) { + final com.microsoft.z3.BitVecExpr leftOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getLeftOp()); + final com.microsoft.z3.BitVecExpr rightOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getRightOp()); + + return context.mkBVXOR(leftOpTerm, rightOpTerm); + } + + private com.microsoft.z3.Expr transformBvNot(final BvNotExpr expr) { + final com.microsoft.z3.BitVecExpr opTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getOp()); + + return context.mkBVNot(opTerm); + } + + private com.microsoft.z3.Expr transformBvShiftLeft(final BvShiftLeftExpr expr) { + final com.microsoft.z3.BitVecExpr leftOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getLeftOp()); + final com.microsoft.z3.BitVecExpr rightOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getRightOp()); + + return context.mkBVSHL(leftOpTerm, rightOpTerm); + } + + private com.microsoft.z3.Expr transformBvShiftRight(final BvShiftRightExpr expr) { + final com.microsoft.z3.BitVecExpr leftOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getLeftOp()); + final com.microsoft.z3.BitVecExpr rightOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getRightOp()); + + if(expr.getType().isSigned()) { + return context.mkBVASHR(leftOpTerm, rightOpTerm); + } else { + return context.mkBVLSHR(leftOpTerm, rightOpTerm); + } + } + private com.microsoft.z3.Expr transformBvGeq(final BvGeqExpr expr) { final com.microsoft.z3.BitVecExpr leftOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getLeftOp()); final com.microsoft.z3.BitVecExpr rightOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getRightOp()); diff --git a/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java b/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java index 70074cb41f..d08106a993 100644 --- a/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java +++ b/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java @@ -286,4 +286,92 @@ public void testBV8() { solver.pop(); } + @Test + public void testBV9() { + final Solver solver = Z3SolverFactory.getInstace().createSolver(); + + final ConstDecl cx = Const("x", BvType(4, false)); + final ConstDecl cy = Const("y", BvType(4, false)); + + solver.push(); + + solver.add(BvExprs.Eq(cy.getRef(), Bv(new boolean[] {false, true, false, false}, false))); + solver.add(BvExprs.Eq(BvExprs.Or(cx.getRef(), cy.getRef()), Bv(new boolean[] {true, true, false, false}, false))); + + SolverStatus status = solver.check(); + assertTrue(status.isSat()); + + Valuation model = solver.getModel(); + assertNotNull(model); + assertNotNull(model.toMap()); + + solver.pop(); + } + + @Test + public void testBV10() { + final Solver solver = Z3SolverFactory.getInstace().createSolver(); + + final ConstDecl cx = Const("x", BvType(4, false)); + final ConstDecl cy = Const("y", BvType(4, false)); + + solver.push(); + + solver.add(BvExprs.Eq(cy.getRef(), Bv(new boolean[] {false, true, false, false}, false))); + solver.add(BvExprs.Eq(BvExprs.And(cx.getRef(), cy.getRef()), Bv(new boolean[] {false, true, false, false}, false))); + + SolverStatus status = solver.check(); + assertTrue(status.isSat()); + + Valuation model = solver.getModel(); + assertNotNull(model); + assertNotNull(model.toMap()); + + solver.pop(); + } + + @Test + public void testBV11() { + final Solver solver = Z3SolverFactory.getInstace().createSolver(); + + final ConstDecl cx = Const("x", BvType(4, false)); + final ConstDecl cy = Const("y", BvType(4, false)); + + solver.push(); + + solver.add(BvExprs.Eq(cy.getRef(), Bv(new boolean[] {false, true, false, false}, false))); + solver.add(BvExprs.Eq(BvExprs.Xor(cx.getRef(), cy.getRef()), Bv(new boolean[] {false, true, false, false}, false))); + + SolverStatus status = solver.check(); + assertTrue(status.isSat()); + + Valuation model = solver.getModel(); + assertNotNull(model); + assertNotNull(model.toMap()); + + solver.pop(); + } + + @Test + public void testBV12() { + final Solver solver = Z3SolverFactory.getInstace().createSolver(); + + final ConstDecl cx = Const("x", BvType(4, false)); + final ConstDecl cy = Const("y", BvType(4, false)); + + solver.push(); + + solver.add(BvExprs.Eq(cy.getRef(), Bv(new boolean[] {false, true, false, false}, false))); + solver.add(BvExprs.Eq(BvExprs.ShiftRight(cy.getRef(), Bv(new boolean[] {false, false, false, true}, false)), cx.getRef())); + + SolverStatus status = solver.check(); + assertTrue(status.isSat()); + + Valuation model = solver.getModel(); + assertNotNull(model); + assertNotNull(model.toMap()); + + solver.pop(); + } + } From 7ad85a6aff57e9e357537b4bdd4a4802f7e16f87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Dobos-Kov=C3=A1cs?= Date: Thu, 2 Apr 2020 15:30:59 +0200 Subject: [PATCH 09/23] Basic bitvector support: cast between bitvectors and integers --- subprojects/cfa/src/test/resources/bv2.cfa | 2 +- .../mit/theta/core/type/bvtype/BvExprs.java | 4 + .../mit/theta/core/type/bvtype/BvLitExpr.java | 5 ++ .../theta/core/type/bvtype/BvToIntExpr.java | 71 +++++++++++++++++ .../mit/theta/core/type/bvtype/BvType.java | 15 +++- .../mit/theta/core/type/inttype/IntExprs.java | 4 + .../theta/core/type/inttype/IntLitExpr.java | 15 ++++ .../theta/core/type/inttype/IntToBvExpr.java | 76 +++++++++++++++++++ .../mit/theta/core/type/inttype/IntType.java | 5 ++ .../theta/solver/z3/Z3ExprTransformer.java | 30 ++++---- 10 files changed, 210 insertions(+), 17 deletions(-) create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvToIntExpr.java create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntToBvExpr.java diff --git a/subprojects/cfa/src/test/resources/bv2.cfa b/subprojects/cfa/src/test/resources/bv2.cfa index 16625cc7a7..c66fab6685 100644 --- a/subprojects/cfa/src/test/resources/bv2.cfa +++ b/subprojects/cfa/src/test/resources/bv2.cfa @@ -8,7 +8,7 @@ main process cfa { final loc END error loc ERR - L0 -> L1 { x := 4'b0001 } + L0 -> L1 { x := 1 + 4'b0000 } L1 -> L2 { assume (x | 4'b0100) /= 4'b0100 } L1 -> L3 { assume not ((x | 4'b0100) /= 4'b0100) } L2 -> L1 { x := x * 4'd2 } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java index aa664e2623..dd3d36f105 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java @@ -96,4 +96,8 @@ public static BvGtExpr Gt(final Expr leftOp, final Expr rightOp) public static BvGeqExpr Geq(final Expr leftOp, final Expr rightOp) { return BvGeqExpr.of(leftOp, rightOp); } + + public static BvToIntExpr ToInt(final Expr op) { + return BvToIntExpr.of(op); + } } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java index 52ef58c1c9..e6a2343f50 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java @@ -3,6 +3,7 @@ import static com.google.common.base.Preconditions.*; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; import static hu.bme.mit.theta.core.type.bvtype.BvExprs.BvType; +import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; import hu.bme.mit.theta.core.model.Valuation; import hu.bme.mit.theta.core.type.LitExpr; @@ -201,6 +202,10 @@ public BoolLitExpr geq(final BvLitExpr that) { return Bool(BvUtils.bvLitExprToBigInteger(this).compareTo(BvUtils.bvLitExprToBigInteger(that)) >= 0); } + public IntLitExpr toInt() { + return Int(BvUtils.bvLitExprToBigInteger(this).intValue()); + } + @Override public int hashCode() { int result = hashCode; diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvToIntExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvToIntExpr.java new file mode 100644 index 0000000000..ad0248d5cf --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvToIntExpr.java @@ -0,0 +1,71 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.abstracttype.CastExpr; +import hu.bme.mit.theta.core.type.inttype.IntLitExpr; +import hu.bme.mit.theta.core.type.inttype.IntType; + +import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; +import static hu.bme.mit.theta.core.utils.TypeUtils.castBv; + +public class BvToIntExpr extends CastExpr { + + private static final int HASH_SEED = 6136; + private static final String OPERATOR_LABEL = "to_int"; + + private BvToIntExpr(final Expr op) { + super(op); + } + + public static BvToIntExpr of(final Expr op) { + return new BvToIntExpr(op); + } + + public static BvToIntExpr create(final Expr op) { + final Expr newOp = castBv(op); + return BvToIntExpr.of(newOp); + } + + @Override + public IntType getType() { + return Int(); + } + + @Override + public IntLitExpr eval(final Valuation val) { + final BvLitExpr opVal = (BvLitExpr) getOp().eval(val); + return opVal.toInt(); + } + + @Override + public BvToIntExpr with(final Expr op) { + if (op == getOp()) { + return this; + } else { + return BvToIntExpr.of(op); + } + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof BvToIntExpr) { + final BvToIntExpr that = (BvToIntExpr) obj; + return this.getOp().equals(that.getOp()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java index ff6f24bd14..f5bb76c963 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java @@ -2,11 +2,15 @@ import hu.bme.mit.theta.common.Utils; import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.Type; import hu.bme.mit.theta.core.type.abstracttype.*; +import hu.bme.mit.theta.core.type.inttype.IntExprs; +import hu.bme.mit.theta.core.type.inttype.IntType; +import hu.bme.mit.theta.core.type.rattype.RatType; import static com.google.common.base.Preconditions.checkArgument; -public final class BvType implements Additive, Multiplicative, Divisible, Equational, Ordered { +public final class BvType implements Additive, Multiplicative, Divisible, Equational, Ordered, Castable { private final static int HASH_SEED = 5674; private final static String TYPE_LABEL = "Bv"; @@ -99,6 +103,15 @@ public GeqExpr Geq(Expr leftOp, Expr rightOp) { return BvGeqExpr.of(leftOp, rightOp); } + @Override + public Expr Cast(final Expr op, final TargetType type) { + if (type instanceof IntType) { + return (Expr) BvExprs.ToInt(op); + } else { + throw new ClassCastException("Bitvector cannot be cast to " + type); + } + } + @Override public int hashCode() { int result = hashCode; diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntExprs.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntExprs.java index fdf90473d2..f0f028b11f 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntExprs.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntExprs.java @@ -36,6 +36,10 @@ public static IntToRatExpr ToRat(final Expr op) { return IntToRatExpr.of(op); } + public static IntToBvExpr ToBv(final Expr op, final int size, final boolean isSigned) { + return IntToBvExpr.of(op, size, isSigned); + } + public static IntAddExpr Add(final Iterable> ops) { return IntAddExpr.of(ops); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntLitExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntLitExpr.java index df66b0c92b..baaca20348 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntLitExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntLitExpr.java @@ -23,7 +23,11 @@ import hu.bme.mit.theta.core.type.LitExpr; import hu.bme.mit.theta.core.type.NullaryExpr; import hu.bme.mit.theta.core.type.booltype.BoolLitExpr; +import hu.bme.mit.theta.core.type.bvtype.BvLitExpr; import hu.bme.mit.theta.core.type.rattype.RatLitExpr; +import hu.bme.mit.theta.core.utils.BvUtils; + +import java.math.BigInteger; public final class IntLitExpr extends NullaryExpr implements LitExpr, Comparable { @@ -58,6 +62,17 @@ public RatLitExpr toRat() { return Rat(this.value, 1); } + public BvLitExpr toBv(int size, boolean isSigned) { + BigInteger res = BigInteger.valueOf(value); + BigInteger fittedRes = BvUtils.fitBigIntegerIntoDomain(res, size, isSigned); + + if(res.equals(fittedRes)) { + return BvUtils.bigIntegerToBvLitExpr(fittedRes, size, isSigned); + } else { + throw new IllegalArgumentException("The value of int " + res.toString() + " does not fit the bitfector " + (isSigned ? "signed" : "unsigned") + " domain of size " + size + " bits"); + } + } + public IntLitExpr add(final IntLitExpr that) { return IntLitExpr.of(this.value + that.value); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntToBvExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntToBvExpr.java new file mode 100644 index 0000000000..770d799ae4 --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntToBvExpr.java @@ -0,0 +1,76 @@ +package hu.bme.mit.theta.core.type.inttype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.abstracttype.CastExpr; +import hu.bme.mit.theta.core.type.bvtype.BvLitExpr; +import hu.bme.mit.theta.core.type.bvtype.BvType; + +import static hu.bme.mit.theta.core.type.bvtype.BvExprs.*; +import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; +import static hu.bme.mit.theta.core.utils.TypeUtils.cast; + +public class IntToBvExpr extends CastExpr { + private static final int HASH_SEED = 9664; + private static final String OPERATOR_LABEL = "to_bv"; + + private final int size; + private final boolean isSigned; + + private IntToBvExpr(final Expr op, int size, boolean isSigned) { + super(op); + this.size = size; + this.isSigned = isSigned; + } + + public static IntToBvExpr of(final Expr op, int size, boolean isSigned) { + return new IntToBvExpr(op, size, isSigned); + } + + public static IntToBvExpr create(final Expr op, int size, boolean isSigned) { + final Expr newOp = cast(op, Int()); + return IntToBvExpr.of(newOp, size, isSigned); + } + + @Override + public BvType getType() { + return BvType(size, isSigned); + } + + @Override + public BvLitExpr eval(final Valuation val) { + final IntLitExpr opVal = (IntLitExpr) getOp().eval(val); + return opVal.toBv(size, isSigned); + } + + @Override + public IntToBvExpr with(final Expr op) { + if (op == getOp()) { + return this; + } else { + return IntToBvExpr.of(op, size, isSigned); + } + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof IntToBvExpr) { + final IntToBvExpr that = (IntToBvExpr) obj; + return this.getOp().equals(that.getOp()); + } else { + return false; + } + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } +} diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntType.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntType.java index 9a4744c44c..d9f2ef0382 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntType.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntType.java @@ -18,6 +18,7 @@ import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.Type; import hu.bme.mit.theta.core.type.abstracttype.*; +import hu.bme.mit.theta.core.type.bvtype.BvType; import hu.bme.mit.theta.core.type.rattype.RatType; public final class IntType implements Additive, Multiplicative, Divisible, Equational, Ordered, @@ -121,6 +122,10 @@ public Expr Cast(final Expr op, f if (type instanceof RatType) { @SuppressWarnings("unchecked") final Expr result = (Expr) IntExprs.ToRat(op); return result; + } else if (type instanceof BvType) { + final BvType bvType = (BvType) type; + @SuppressWarnings("unchecked") final Expr result = (Expr) IntExprs.ToBv(op, bvType.getSize(), bvType.isSigned()); + return result; } else { throw new ClassCastException("Int cannot be cast to " + type); } diff --git a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java index 4b760d3f91..147847c0c9 100644 --- a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java +++ b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java @@ -52,21 +52,7 @@ import hu.bme.mit.theta.core.type.bvtype.*; import hu.bme.mit.theta.core.type.functype.FuncAppExpr; import hu.bme.mit.theta.core.type.functype.FuncType; -import hu.bme.mit.theta.core.type.inttype.IntAddExpr; -import hu.bme.mit.theta.core.type.inttype.IntDivExpr; -import hu.bme.mit.theta.core.type.inttype.IntEqExpr; -import hu.bme.mit.theta.core.type.inttype.IntGeqExpr; -import hu.bme.mit.theta.core.type.inttype.IntGtExpr; -import hu.bme.mit.theta.core.type.inttype.IntLeqExpr; -import hu.bme.mit.theta.core.type.inttype.IntLitExpr; -import hu.bme.mit.theta.core.type.inttype.IntLtExpr; -import hu.bme.mit.theta.core.type.inttype.IntMulExpr; -import hu.bme.mit.theta.core.type.inttype.IntNegExpr; -import hu.bme.mit.theta.core.type.inttype.IntNeqExpr; -import hu.bme.mit.theta.core.type.inttype.IntSubExpr; -import hu.bme.mit.theta.core.type.inttype.IntToRatExpr; -import hu.bme.mit.theta.core.type.inttype.IntModExpr; -import hu.bme.mit.theta.core.type.inttype.IntRemExpr; +import hu.bme.mit.theta.core.type.inttype.*; import hu.bme.mit.theta.core.type.rattype.RatAddExpr; import hu.bme.mit.theta.core.type.rattype.RatDivExpr; import hu.bme.mit.theta.core.type.rattype.RatEqExpr; @@ -187,6 +173,8 @@ public Z3ExprTransformer(final Z3TransformationManager transformer, final Contex .addCase(IntToRatExpr.class, this::transformIntToRat) + .addCase(IntToBvExpr.class, this::transformIntToBv) + // Bitvectors .addCase(BvLitExpr.class, this::transformBvLit) @@ -229,6 +217,8 @@ public Z3ExprTransformer(final Z3TransformationManager transformer, final Contex .addCase(BvLtExpr.class, this::transformBvLt) + .addCase(BvToIntExpr.class, this::transformBvToInt) + // Functions .addCase(FuncAppExpr.class, this::transformFuncApp) @@ -531,6 +521,11 @@ private com.microsoft.z3.Expr transformIntToRat(final IntToRatExpr expr) { return context.mkInt2Real(opTerm); } + private com.microsoft.z3.Expr transformIntToBv(final IntToBvExpr expr) { + final com.microsoft.z3.IntExpr opTerm = (com.microsoft.z3.IntExpr) toTerm(expr.getOp()); + return context.mkInt2BV(expr.getType().getSize(), opTerm); + } + /* * Bitvectors */ @@ -705,6 +700,11 @@ private com.microsoft.z3.Expr transformBvLt(final BvLtExpr expr) { } } + private com.microsoft.z3.Expr transformBvToInt(final BvToIntExpr expr) { + final com.microsoft.z3.BitVecExpr opTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getOp()); + return context.mkBV2Int(opTerm, expr.getOp().getType().isSigned()); + } + /* * Arrays */ From f6252cf9f4aa82008e21fae2ce26f0f7c0fe3462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Dobos-Kov=C3=A1cs?= Date: Thu, 2 Apr 2020 18:03:14 +0200 Subject: [PATCH 10/23] Refactor: make bitvector add, or, xor multiary --- .../mit/theta/core/type/bvtype/BvAndExpr.java | 49 +++++++++---------- .../mit/theta/core/type/bvtype/BvExprs.java | 12 ++--- .../mit/theta/core/type/bvtype/BvLitExpr.java | 10 +++- .../mit/theta/core/type/bvtype/BvOrExpr.java | 48 +++++++++--------- .../mit/theta/core/type/bvtype/BvXorExpr.java | 48 +++++++++--------- 5 files changed, 80 insertions(+), 87 deletions(-) diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAndExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAndExpr.java index 17c7fa1752..9aa97b008b 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAndExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAndExpr.java @@ -1,27 +1,30 @@ package hu.bme.mit.theta.core.type.bvtype; import hu.bme.mit.theta.core.model.Valuation; -import hu.bme.mit.theta.core.type.BinaryExpr; import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.MultiaryExpr; +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.collect.ImmutableList.toImmutableList; import static hu.bme.mit.theta.core.utils.TypeUtils.cast; -public class BvAndExpr extends BinaryExpr { +public class BvAndExpr extends MultiaryExpr { private static final int HASH_SEED = 9125; private static final String OPERATOR_LABEL = "&"; - private BvAndExpr(final Expr leftOp, final Expr rightOp) { - super(leftOp, rightOp); + private BvAndExpr(final Iterable> ops) { + super(ops); } - public static BvAndExpr of(final Expr leftOp, final Expr rightOp) { - return new BvAndExpr(leftOp, rightOp); + public static BvAndExpr of(final Iterable> ops) { + return new BvAndExpr(ops); } - public static BvAndExpr create(final Expr leftOp, final Expr rightOp) { - final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); - final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); - return BvAndExpr.of(newLeftOp, newRightOp); + public static BvAndExpr create(final List> ops) { + checkArgument(!ops.isEmpty()); + return BvAndExpr.of(ops.stream().map(op -> cast(op, (BvType) ops.get(0).getType())).collect(toImmutableList())); } @Override @@ -31,37 +34,29 @@ public BvType getType() { @Override public BvLitExpr eval(final Valuation val) { - final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); - final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); - return leftOpVal.and(rightOpVal); + return getOps().stream().skip(1).reduce( + (BvLitExpr) getOps().get(0).eval(val), + (op1, op2) -> (op1.and((BvLitExpr) op2.eval(val))), + BvLitExpr::and + ); } @Override - public BvAndExpr with(final Expr leftOp, final Expr rightOp) { - if (leftOp == getLeftOp() && rightOp == getRightOp()) { + public BvAndExpr with(final Iterable> ops) { + if (ops == getOps()) { return this; } else { - return BvAndExpr.of(leftOp, rightOp); + return BvAndExpr.of(ops); } } - @Override - public BvAndExpr withLeftOp(final Expr leftOp) { - return with(leftOp, getRightOp()); - } - - @Override - public BvAndExpr withRightOp(final Expr rightOp) { - return with(getLeftOp(), rightOp); - } - @Override public boolean equals(final Object obj) { if (this == obj) { return true; } else if (obj instanceof BvAndExpr) { final BvAndExpr that = (BvAndExpr) obj; - return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); + return this.getOps().equals(that.getOps()); } else { return false; } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java index dd3d36f105..8ae7fbe9da 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java @@ -49,16 +49,16 @@ public static BvRemExpr Rem(final Expr leftOp, final Expr rightO return BvRemExpr.of(leftOp, rightOp); } - public static BvOrExpr Or(final Expr leftOp, final Expr rightOp) { - return BvOrExpr.of(leftOp, rightOp); + public static BvOrExpr Or(final List> ops) { + return BvOrExpr.of(ops); } - public static BvAndExpr And(final Expr leftOp, final Expr rightOp) { - return BvAndExpr.of(leftOp, rightOp); + public static BvAndExpr And(final List> ops) { + return BvAndExpr.of(ops); } - public static BvXorExpr Xor(final Expr leftOp, final Expr rightOp) { - return BvXorExpr.of(leftOp, rightOp); + public static BvXorExpr Xor(final List> ops) { + return BvXorExpr.of(ops); } public static BvNotExpr Not(final Expr op) { diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java index e6a2343f50..c566f8b523 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java @@ -15,7 +15,7 @@ import java.math.BigInteger; import java.util.Arrays; -public final class BvLitExpr extends NullaryExpr implements LitExpr { +public final class BvLitExpr extends NullaryExpr implements LitExpr, Comparable { private static final int HASH_SEED = 5624; private volatile int hashCode = 0; @@ -123,7 +123,7 @@ public BvLitExpr shiftRight(final BvLitExpr that) { checkArgument(this.getType().equals(that.getType())); BigInteger shift = BvUtils.bvLitExprToBigInteger(this); for(BigInteger i = BigInteger.ZERO; i.compareTo(BvUtils.bvLitExprToBigInteger(that)) < 0; i = i.add(BigInteger.ONE)) { - shift = shift.multiply(BigInteger.TWO); + shift = shift.divide(BigInteger.TWO); } return BvUtils.bigIntegerToBvLitExpr(shift, getType().getSize(), getType().isSigned()); } @@ -239,4 +239,10 @@ public String toString() { .replace(",", "") .replace(" ", ""); } + + @Override + public int compareTo(final BvLitExpr that) { + checkArgument(this.getType().equals(that.getType())); + return BvUtils.bvLitExprToBigInteger(this).compareTo(BvUtils.bvLitExprToBigInteger(that)); + } } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvOrExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvOrExpr.java index 882394281e..af8665b6eb 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvOrExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvOrExpr.java @@ -3,25 +3,29 @@ import hu.bme.mit.theta.core.model.Valuation; import hu.bme.mit.theta.core.type.BinaryExpr; import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.MultiaryExpr; +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.collect.ImmutableList.toImmutableList; import static hu.bme.mit.theta.core.utils.TypeUtils.cast; -public class BvOrExpr extends BinaryExpr { +public class BvOrExpr extends MultiaryExpr { private static final int HASH_SEED = 2745; private static final String OPERATOR_LABEL = "|"; - private BvOrExpr(final Expr leftOp, final Expr rightOp) { - super(leftOp, rightOp); + private BvOrExpr(final Iterable> ops) { + super(ops); } - public static BvOrExpr of(final Expr leftOp, final Expr rightOp) { - return new BvOrExpr(leftOp, rightOp); + public static BvOrExpr of(final Iterable> ops) { + return new BvOrExpr(ops); } - public static BvOrExpr create(final Expr leftOp, final Expr rightOp) { - final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); - final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); - return BvOrExpr.of(newLeftOp, newRightOp); + public static BvOrExpr create(final List> ops) { + checkArgument(!ops.isEmpty()); + return BvOrExpr.of(ops.stream().map(op -> cast(op, (BvType) ops.get(0).getType())).collect(toImmutableList())); } @Override @@ -31,37 +35,29 @@ public BvType getType() { @Override public BvLitExpr eval(final Valuation val) { - final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); - final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); - return leftOpVal.or(rightOpVal); + return getOps().stream().skip(1).reduce( + (BvLitExpr) getOps().get(0).eval(val), + (op1, op2) -> (op1.or((BvLitExpr) op2.eval(val))), + BvLitExpr::or + ); } @Override - public BvOrExpr with(final Expr leftOp, final Expr rightOp) { - if (leftOp == getLeftOp() && rightOp == getRightOp()) { + public BvOrExpr with(final Iterable> ops) { + if (ops == getOps()) { return this; } else { - return BvOrExpr.of(leftOp, rightOp); + return BvOrExpr.of(ops); } } - @Override - public BvOrExpr withLeftOp(final Expr leftOp) { - return with(leftOp, getRightOp()); - } - - @Override - public BvOrExpr withRightOp(final Expr rightOp) { - return with(getLeftOp(), rightOp); - } - @Override public boolean equals(final Object obj) { if (this == obj) { return true; } else if (obj instanceof BvOrExpr) { final BvOrExpr that = (BvOrExpr) obj; - return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); + return this.getOps().equals(that.getOps()); } else { return false; } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvXorExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvXorExpr.java index 5e5d861bb5..af4b3ba809 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvXorExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvXorExpr.java @@ -3,25 +3,29 @@ import hu.bme.mit.theta.core.model.Valuation; import hu.bme.mit.theta.core.type.BinaryExpr; import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.MultiaryExpr; +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.collect.ImmutableList.toImmutableList; import static hu.bme.mit.theta.core.utils.TypeUtils.cast; -public class BvXorExpr extends BinaryExpr { +public class BvXorExpr extends MultiaryExpr { private static final int HASH_SEED = 9457; private static final String OPERATOR_LABEL = "^"; - private BvXorExpr(final Expr leftOp, final Expr rightOp) { - super(leftOp, rightOp); + private BvXorExpr(final Iterable> ops) { + super(ops); } - public static BvXorExpr of(final Expr leftOp, final Expr rightOp) { - return new BvXorExpr(leftOp, rightOp); + public static BvXorExpr of(final Iterable> ops) { + return new BvXorExpr(ops); } - public static BvXorExpr create(final Expr leftOp, final Expr rightOp) { - final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); - final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); - return BvXorExpr.of(newLeftOp, newRightOp); + public static BvXorExpr create(final List> ops) { + checkArgument(!ops.isEmpty()); + return BvXorExpr.of(ops.stream().map(op -> cast(op, (BvType) ops.get(0).getType())).collect(toImmutableList())); } @Override @@ -31,37 +35,29 @@ public BvType getType() { @Override public BvLitExpr eval(final Valuation val) { - final BvLitExpr leftOpVal = (BvLitExpr) getLeftOp().eval(val); - final BvLitExpr rightOpVal = (BvLitExpr) getRightOp().eval(val); - return leftOpVal.xor(rightOpVal); + return getOps().stream().skip(1).reduce( + (BvLitExpr) getOps().get(0).eval(val), + (op1, op2) -> (op1.xor((BvLitExpr) op2.eval(val))), + BvLitExpr::xor + ); } @Override - public BvXorExpr with(final Expr leftOp, final Expr rightOp) { - if (leftOp == getLeftOp() && rightOp == getRightOp()) { + public BvXorExpr with(final Iterable> ops) { + if (ops == getOps()) { return this; } else { - return BvXorExpr.of(leftOp, rightOp); + return BvXorExpr.of(ops); } } - @Override - public BvXorExpr withLeftOp(final Expr leftOp) { - return with(leftOp, getRightOp()); - } - - @Override - public BvXorExpr withRightOp(final Expr rightOp) { - return with(getLeftOp(), rightOp); - } - @Override public boolean equals(final Object obj) { if (this == obj) { return true; } else if (obj instanceof BvXorExpr) { final BvXorExpr that = (BvXorExpr) obj; - return this.getLeftOp().equals(that.getLeftOp()) && this.getRightOp().equals(that.getRightOp()); + return this.getOps().equals(that.getOps()); } else { return false; } From e4c453f91002073f36e9fbb5594f43f41c78d4fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Dobos-Kov=C3=A1cs?= Date: Thu, 2 Apr 2020 18:03:39 +0200 Subject: [PATCH 11/23] Basic bitvector support: simplifying expressions --- .../hu/bme/mit/theta/core/utils/BvUtils.java | 4 +- .../mit/theta/core/utils/ExprSimplifier.java | 522 +++++++++++++++++- .../theta/core/utils/ExprSimplifierTest.java | 377 +++++++++++++ 3 files changed, 886 insertions(+), 17 deletions(-) diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/BvUtils.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/BvUtils.java index 3d8515a66b..2079ee609a 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/BvUtils.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/BvUtils.java @@ -21,7 +21,7 @@ public static BigInteger bvLitExprToBigInteger(final BvLitExpr expr) { } if(expr.getType().isSigned() && expr.getValue()[0]) { - integer = integer.subtract(BigInteger.TWO.multiply(BigInteger.valueOf(expr.getType().getSize()-1))); + integer = integer.subtract(BigInteger.TWO.pow(expr.getType().getSize())); } return integer; @@ -29,7 +29,7 @@ public static BigInteger bvLitExprToBigInteger(final BvLitExpr expr) { public static BvLitExpr bigIntegerToBvLitExpr(BigInteger integer, final int size, final boolean isSigned) { if(isSigned && integer.compareTo(BigInteger.ZERO) < 0) { - integer = integer.add(BigInteger.TWO.multiply(BigInteger.valueOf(size-1))); + integer = integer.add(BigInteger.TWO.pow(size)); } boolean[] values = new boolean[size]; diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java index c3fb57fc4b..2d7d4cad54 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java @@ -19,6 +19,7 @@ import static hu.bme.mit.theta.core.type.booltype.BoolExprs.False; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Not; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.True; +import static hu.bme.mit.theta.core.type.bvtype.BvExprs.Bv; import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; import static hu.bme.mit.theta.core.type.rattype.RatExprs.Rat; @@ -45,21 +46,8 @@ import hu.bme.mit.theta.core.type.booltype.OrExpr; import hu.bme.mit.theta.core.type.booltype.TrueExpr; import hu.bme.mit.theta.core.type.booltype.XorExpr; -import hu.bme.mit.theta.core.type.inttype.IntAddExpr; -import hu.bme.mit.theta.core.type.inttype.IntDivExpr; -import hu.bme.mit.theta.core.type.inttype.IntEqExpr; -import hu.bme.mit.theta.core.type.inttype.IntGeqExpr; -import hu.bme.mit.theta.core.type.inttype.IntGtExpr; -import hu.bme.mit.theta.core.type.inttype.IntLeqExpr; -import hu.bme.mit.theta.core.type.inttype.IntLitExpr; -import hu.bme.mit.theta.core.type.inttype.IntLtExpr; -import hu.bme.mit.theta.core.type.inttype.IntMulExpr; -import hu.bme.mit.theta.core.type.inttype.IntNegExpr; -import hu.bme.mit.theta.core.type.inttype.IntNeqExpr; -import hu.bme.mit.theta.core.type.inttype.IntSubExpr; -import hu.bme.mit.theta.core.type.inttype.IntToRatExpr; -import hu.bme.mit.theta.core.type.inttype.IntType; -import hu.bme.mit.theta.core.type.inttype.IntModExpr; +import hu.bme.mit.theta.core.type.bvtype.*; +import hu.bme.mit.theta.core.type.inttype.*; import hu.bme.mit.theta.core.type.rattype.RatAddExpr; import hu.bme.mit.theta.core.type.rattype.RatDivExpr; import hu.bme.mit.theta.core.type.rattype.RatEqExpr; @@ -120,6 +108,8 @@ public final class ExprSimplifier { .addCase(IntToRatExpr.class, ExprSimplifier::simplifyIntToRat) + .addCase(IntToBvExpr.class, ExprSimplifier::simplifyIntToBv) + .addCase(IntAddExpr.class, ExprSimplifier::simplifyIntAdd) .addCase(IntSubExpr.class, ExprSimplifier::simplifyIntSub) @@ -144,6 +134,48 @@ public final class ExprSimplifier { .addCase(IntLtExpr.class, ExprSimplifier::simplifyIntLt) + // Bitvectors + + .addCase(BvAddExpr.class, ExprSimplifier::simplifyBvAdd) + + .addCase(BvSubExpr.class, ExprSimplifier::simplifyBvSub) + + .addCase(BvNegExpr.class, ExprSimplifier::simplifyBvNeg) + + .addCase(BvMulExpr.class, ExprSimplifier::simplifyBvMul) + + .addCase(BvDivExpr.class, ExprSimplifier::simplifyBvDiv) + + .addCase(BvModExpr.class, ExprSimplifier::simplifyBvMod) + + .addCase(BvRemExpr.class, ExprSimplifier::simplifyBvRem) + + .addCase(BvAndExpr.class, ExprSimplifier::simplifyBvAnd) + + .addCase(BvOrExpr.class, ExprSimplifier::simplifyBvOr) + + .addCase(BvXorExpr.class, ExprSimplifier::simplifyBvXor) + + .addCase(BvNotExpr.class, ExprSimplifier::simplifyBvNot) + + .addCase(BvShiftLeftExpr.class, ExprSimplifier::simplifyBvShiftLeft) + + .addCase(BvShiftRightExpr.class, ExprSimplifier::simplifyBvShiftRight) + + .addCase(BvEqExpr.class, ExprSimplifier::simplifyBvEq) + + .addCase(BvNeqExpr.class, ExprSimplifier::simplifyBvNeq) + + .addCase(BvGeqExpr.class, ExprSimplifier::simplifyBvGeq) + + .addCase(BvGtExpr.class, ExprSimplifier::simplifyBvGt) + + .addCase(BvLeqExpr.class, ExprSimplifier::simplifyBvLeq) + + .addCase(BvLtExpr.class, ExprSimplifier::simplifyBvLt) + + .addCase(BvToIntExpr.class, ExprSimplifier::simplifyBvToInt) + // General .addCase(RefExpr.class, ExprSimplifier::simplifyRef) @@ -623,6 +655,17 @@ private static Expr simplifyIntToRat(final IntToRatExpr expr, final Val return expr.with(op); } + private static Expr simplifyIntToBv(final IntToBvExpr expr, final Valuation val) { + final Expr op = simplify(expr.getOp(), val); + + if (op instanceof IntLitExpr) { + final IntLitExpr litOp = (IntLitExpr) op; + return litOp.toBv(expr.getType().getSize(), expr.getType().isSigned()); + } + + return expr.with(op); + } + private static Expr simplifyIntAdd(final IntAddExpr expr, final Valuation val) { final List> ops = new ArrayList<>(); @@ -865,4 +908,453 @@ private static Expr simplifyIntLt(final IntLtExpr expr, final Valuatio return expr.with(leftOp, rightOp); } + /* + * Bitvectors + */ + + private static Expr simplifyBvAdd(final BvAddExpr expr, final Valuation val) { + final List> ops = new ArrayList<>(); + + for (final Expr op : expr.getOps()) { + final Expr opVisited = simplify(op, val); + if (opVisited instanceof BvAddExpr) { + final BvAddExpr addOp = (BvAddExpr) opVisited; + ops.addAll(addOp.getOps()); + } else { + ops.add(opVisited); + } + } + BvLitExpr value = Bv(new boolean[expr.getType().getSize()], expr.getType().isSigned()); + + for (final Iterator> iterator = ops.iterator(); iterator.hasNext(); ) { + final Expr op = iterator.next(); + if (op instanceof BvLitExpr) { + final BvLitExpr litOp = (BvLitExpr) op; + value = value.add(litOp); + iterator.remove(); + } + } + + if (!value.eq(Bv(new boolean[expr.getType().getSize()], expr.getType().isSigned())).getValue()) { + ops.add(value); + } + + if (ops.isEmpty()) { + return Bv(new boolean[expr.getType().getSize()], expr.getType().isSigned()); + } else if (ops.size() == 1) { + return Utils.singleElementOf(ops); + } + + return expr.with(ops); + } + + private static Expr simplifyBvSub(final BvSubExpr expr, final Valuation val) { + final Expr leftOp = simplify(expr.getLeftOp(), val); + final Expr rightOp = simplify(expr.getRightOp(), val); + + if (leftOp instanceof BvLitExpr && rightOp instanceof BvLitExpr) { + final BvLitExpr leftLit = (BvLitExpr) leftOp; + final BvLitExpr rightLit = (BvLitExpr) rightOp; + return leftLit.sub(rightLit); + } + + if (leftOp instanceof RefExpr && rightOp instanceof RefExpr) { + if (leftOp.equals(rightOp)) { + return Bv(new boolean[expr.getType().getSize()], expr.getType().isSigned()); + } + } + + return expr.with(leftOp, rightOp); + } + + private static Expr simplifyBvNeg(final BvNegExpr expr, final Valuation val) { + final Expr op = simplify(expr.getOp(), val); + + if (op instanceof BvLitExpr) { + final BvLitExpr litOp = (BvLitExpr) op; + return litOp.neg(); + } else if (op instanceof BvNegExpr) { + final BvNegExpr negOp = (BvNegExpr) op; + return negOp.getOp(); + } + + return expr.with(op); + } + + private static Expr simplifyBvMul(final BvMulExpr expr, final Valuation val) { + final List> ops = new ArrayList<>(); + + for (final Expr op : expr.getOps()) { + final Expr opVisited = simplify(op, val); + if (opVisited instanceof BvMulExpr) { + final BvMulExpr mulOp = (BvMulExpr) opVisited; + ops.addAll(mulOp.getOps()); + } else { + ops.add(opVisited); + } + } + + final BvLitExpr ZERO = Bv(new boolean[expr.getType().getSize()], expr.getType().isSigned()); + final BvLitExpr ONE = Bv(new boolean[expr.getType().getSize()], expr.getType().isSigned()); + ONE.getValue()[expr.getType().getSize()-1] = true; // 1 + + BvLitExpr value = ONE; + for (final Iterator> iterator = ops.iterator(); iterator.hasNext(); ) { + final Expr op = iterator.next(); + if (op instanceof BvLitExpr) { + final BvLitExpr litOp = (BvLitExpr) op; + value = value.mul(litOp); + iterator.remove(); + if (value.equals(ZERO)) { + return ZERO; + } + } + } + + if (!value.equals(ONE)) { + ops.add(0, value); + } + + if (ops.isEmpty()) { + return ONE; + } else if (ops.size() == 1) { + return Utils.singleElementOf(ops); + } + + return expr.with(ops); + } + + private static Expr simplifyBvDiv(final BvDivExpr expr, final Valuation val) { + final Expr leftOp = simplify(expr.getLeftOp(), val); + final Expr rightOp = simplify(expr.getRightOp(), val); + + if (leftOp instanceof BvLitExpr && rightOp instanceof BvLitExpr) { + final BvLitExpr leftLit = (BvLitExpr) leftOp; + final BvLitExpr rightLit = (BvLitExpr) rightOp; + return leftLit.div(rightLit); + } + + if (leftOp instanceof RefExpr && rightOp instanceof RefExpr) { + if (leftOp.equals(rightOp)) { + final BvLitExpr ONE = Bv(new boolean[expr.getType().getSize()], expr.getType().isSigned()); + ONE.getValue()[expr.getType().getSize()-1] = true; // 1 + return ONE; + } + } + + return expr.with(leftOp, rightOp); + } + + private static Expr simplifyBvMod(final BvModExpr expr, final Valuation val) { + final Expr leftOp = simplify(expr.getLeftOp(), val); + final Expr rightOp = simplify(expr.getRightOp(), val); + + if (leftOp instanceof BvLitExpr && rightOp instanceof BvLitExpr) { + final BvLitExpr leftLit = (BvLitExpr) leftOp; + final BvLitExpr rightLit = (BvLitExpr) rightOp; + return leftLit.mod(rightLit); + } + + if (leftOp instanceof RefExpr && rightOp instanceof RefExpr) { + if (leftOp.equals(rightOp)) { + return Bv(new boolean[expr.getType().getSize()], expr.getType().isSigned()); + } + } + + return expr.with(leftOp, rightOp); + } + + private static Expr simplifyBvRem(final BvRemExpr expr, final Valuation val) { + final Expr leftOp = simplify(expr.getLeftOp(), val); + final Expr rightOp = simplify(expr.getRightOp(), val); + + if (leftOp instanceof BvLitExpr && rightOp instanceof BvLitExpr) { + final BvLitExpr leftLit = (BvLitExpr) leftOp; + final BvLitExpr rightLit = (BvLitExpr) rightOp; + return leftLit.rem(rightLit); + } + + if (leftOp instanceof RefExpr && rightOp instanceof RefExpr) { + if (leftOp.equals(rightOp)) { + return Bv(new boolean[expr.getType().getSize()], expr.getType().isSigned()); + } + } + + return expr.with(leftOp, rightOp); + } + + private static Expr simplifyBvAnd(final BvAndExpr expr, final Valuation val) { + final List> ops = new ArrayList<>(); + + for (final Expr op : expr.getOps()) { + final Expr opVisited = simplify(op, val); + if (opVisited instanceof BvAndExpr) { + final BvAndExpr addOp = (BvAndExpr) opVisited; + ops.addAll(addOp.getOps()); + } else { + ops.add(opVisited); + } + } + BvLitExpr ONES = Bv(new boolean[expr.getType().getSize()], expr.getType().isSigned()); + for(int i = 0; i < expr.getType().getSize(); i++) { + ONES.getValue()[i] = true; + } + + BvLitExpr value = ONES; + + for (final Iterator> iterator = ops.iterator(); iterator.hasNext(); ) { + final Expr op = iterator.next(); + if (op instanceof BvLitExpr) { + final BvLitExpr litOp = (BvLitExpr) op; + value = value.and(litOp); + iterator.remove(); + } + } + + if (!value.equals(ONES)) { + ops.add(value); + } + + if (ops.isEmpty()) { + return ONES; + } else if (ops.size() == 1) { + return Utils.singleElementOf(ops); + } + + return expr.with(ops); + } + + private static Expr simplifyBvOr(final BvOrExpr expr, final Valuation val) { + final List> ops = new ArrayList<>(); + + for (final Expr op : expr.getOps()) { + final Expr opVisited = simplify(op, val); + if (opVisited instanceof BvOrExpr) { + final BvOrExpr addOp = (BvOrExpr) opVisited; + ops.addAll(addOp.getOps()); + } else { + ops.add(opVisited); + } + } + BvLitExpr ZEROS = Bv(new boolean[expr.getType().getSize()], expr.getType().isSigned()); + + BvLitExpr value = ZEROS; + + for (final Iterator> iterator = ops.iterator(); iterator.hasNext(); ) { + final Expr op = iterator.next(); + if (op instanceof BvLitExpr) { + final BvLitExpr litOp = (BvLitExpr) op; + value = value.or(litOp); + iterator.remove(); + } + } + + if (!value.equals(ZEROS)) { + ops.add(value); + } + + if (ops.isEmpty()) { + return ZEROS; + } else if (ops.size() == 1) { + return Utils.singleElementOf(ops); + } + + return expr.with(ops); + } + + private static Expr simplifyBvXor(final BvXorExpr expr, final Valuation val) { + final List> ops = new ArrayList<>(); + + for (final Expr op : expr.getOps()) { + final Expr opVisited = simplify(op, val); + if (opVisited instanceof BvXorExpr) { + final BvXorExpr addOp = (BvXorExpr) opVisited; + ops.addAll(addOp.getOps()); + } else { + ops.add(opVisited); + } + } + BvLitExpr ZEROS = Bv(new boolean[expr.getType().getSize()], expr.getType().isSigned()); + + BvLitExpr value = ZEROS; + + for (final Iterator> iterator = ops.iterator(); iterator.hasNext(); ) { + final Expr op = iterator.next(); + if (op instanceof BvLitExpr) { + final BvLitExpr litOp = (BvLitExpr) op; + value = value.xor(litOp); + iterator.remove(); + } + } + + if (!value.equals(ZEROS)) { + ops.add(value); + } + + if (ops.isEmpty()) { + return ZEROS; + } else if (ops.size() == 1) { + return Utils.singleElementOf(ops); + } + + return expr.with(ops); + } + + private static Expr simplifyBvNot(final BvNotExpr expr, final Valuation val) { + final Expr op = simplify(expr.getOp(), val); + + if (op instanceof BvLitExpr) { + final BvLitExpr litOp = (BvLitExpr) op; + return litOp.not(); + } else if (op instanceof BvNotExpr) { + final BvNotExpr notOp = (BvNotExpr) op; + return notOp.getOp(); + } + + return expr.with(op); + } + + private static Expr simplifyBvShiftLeft(final BvShiftLeftExpr expr, final Valuation val) { + final Expr leftOp = simplify(expr.getLeftOp(), val); + final Expr rightOp = simplify(expr.getRightOp(), val); + + if (leftOp instanceof BvLitExpr && rightOp instanceof BvLitExpr) { + final BvLitExpr leftLit = (BvLitExpr) leftOp; + final BvLitExpr rightLit = (BvLitExpr) rightOp; + return leftLit.shiftLeft(rightLit); + } + + return expr.with(leftOp, rightOp); + } + + private static Expr simplifyBvShiftRight(final BvShiftRightExpr expr, final Valuation val) { + final Expr leftOp = simplify(expr.getLeftOp(), val); + final Expr rightOp = simplify(expr.getRightOp(), val); + + if (leftOp instanceof BvLitExpr && rightOp instanceof BvLitExpr) { + final BvLitExpr leftLit = (BvLitExpr) leftOp; + final BvLitExpr rightLit = (BvLitExpr) rightOp; + return leftLit.shiftRight(rightLit); + } + + return expr.with(leftOp, rightOp); + } + + private static Expr simplifyBvEq(final BvEqExpr expr, final Valuation val) { + final Expr leftOp = simplify(expr.getLeftOp(), val); + final Expr rightOp = simplify(expr.getRightOp(), val); + + if (leftOp instanceof BvLitExpr && rightOp instanceof BvLitExpr) { + return Bool(leftOp.equals(rightOp)); + } else if (leftOp instanceof RefExpr && rightOp instanceof RefExpr) { + if (leftOp.equals(rightOp)) { + return True(); + } + } + + return expr.with(leftOp, rightOp); + } + + private static Expr simplifyBvNeq(final BvNeqExpr expr, final Valuation val) { + final Expr leftOp = simplify(expr.getLeftOp(), val); + final Expr rightOp = simplify(expr.getRightOp(), val); + + if (leftOp instanceof BvLitExpr && rightOp instanceof BvLitExpr) { + return Bool(!leftOp.equals(rightOp)); + } else if (leftOp instanceof RefExpr && rightOp instanceof RefExpr) { + if (leftOp.equals(rightOp)) { + return False(); + } + } + + return expr.with(leftOp, rightOp); + } + + private static Expr simplifyBvGeq(final BvGeqExpr expr, final Valuation val) { + final Expr leftOp = simplify(expr.getLeftOp(), val); + final Expr rightOp = simplify(expr.getRightOp(), val); + + if (leftOp instanceof BvLitExpr && rightOp instanceof BvLitExpr) { + final BvLitExpr leftLit = (BvLitExpr) leftOp; + final BvLitExpr rightLit = (BvLitExpr) rightOp; + return Bool(leftLit.compareTo(rightLit) >= 0); + } + + if (leftOp instanceof RefExpr && rightOp instanceof RefExpr) { + if (leftOp.equals(rightOp)) { + return True(); + } + } + + return expr.with(leftOp, rightOp); + } + + private static Expr simplifyBvGt(final BvGtExpr expr, final Valuation val) { + final Expr leftOp = simplify(expr.getLeftOp(), val); + final Expr rightOp = simplify(expr.getRightOp(), val); + + if (leftOp instanceof BvLitExpr && rightOp instanceof BvLitExpr) { + final BvLitExpr leftLit = (BvLitExpr) leftOp; + final BvLitExpr rightLit = (BvLitExpr) rightOp; + return Bool(leftLit.compareTo(rightLit) > 0); + } + + if (leftOp instanceof RefExpr && rightOp instanceof RefExpr) { + if (leftOp.equals(rightOp)) { + return False(); + } + } + + return expr.with(leftOp, rightOp); + } + + private static Expr simplifyBvLeq(final BvLeqExpr expr, final Valuation val) { + final Expr leftOp = simplify(expr.getLeftOp(), val); + final Expr rightOp = simplify(expr.getRightOp(), val); + + if (leftOp instanceof BvLitExpr && rightOp instanceof BvLitExpr) { + final BvLitExpr leftLit = (BvLitExpr) leftOp; + final BvLitExpr rightLit = (BvLitExpr) rightOp; + return Bool(leftLit.compareTo(rightLit) <= 0); + } + + if (leftOp instanceof RefExpr && rightOp instanceof RefExpr) { + if (leftOp.equals(rightOp)) { + return True(); + } + } + + return expr.with(leftOp, rightOp); + } + + private static Expr simplifyBvLt(final BvLtExpr expr, final Valuation val) { + final Expr leftOp = simplify(expr.getLeftOp(), val); + final Expr rightOp = simplify(expr.getRightOp(), val); + + if (leftOp instanceof BvLitExpr && rightOp instanceof BvLitExpr) { + final BvLitExpr leftLit = (BvLitExpr) leftOp; + final BvLitExpr rightLit = (BvLitExpr) rightOp; + return Bool(leftLit.compareTo(rightLit) < 0); + } + + if (leftOp instanceof RefExpr && rightOp instanceof RefExpr) { + if (leftOp.equals(rightOp)) { + return False(); + } + } + + return expr.with(leftOp, rightOp); + } + + private static Expr simplifyBvToInt(final BvToIntExpr expr, final Valuation val) { + final Expr op = simplify(expr.getOp(), val); + + if (op instanceof BvLitExpr) { + final BvLitExpr litOp = (BvLitExpr) op; + return litOp.toInt(); + } + + return expr.with(op); + } + } diff --git a/subprojects/core/src/test/java/hu/bme/mit/theta/core/utils/ExprSimplifierTest.java b/subprojects/core/src/test/java/hu/bme/mit/theta/core/utils/ExprSimplifierTest.java index d0c52e54ac..4a16d9bd1d 100644 --- a/subprojects/core/src/test/java/hu/bme/mit/theta/core/utils/ExprSimplifierTest.java +++ b/subprojects/core/src/test/java/hu/bme/mit/theta/core/utils/ExprSimplifierTest.java @@ -26,6 +26,8 @@ import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Or; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.True; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Xor; +import static hu.bme.mit.theta.core.type.bvtype.BvExprs.Bv; +import static hu.bme.mit.theta.core.type.bvtype.BvExprs.BvType; import static hu.bme.mit.theta.core.type.inttype.IntExprs.Add; import static hu.bme.mit.theta.core.type.inttype.IntExprs.Div; import static hu.bme.mit.theta.core.type.inttype.IntExprs.Eq; @@ -55,6 +57,9 @@ import static hu.bme.mit.theta.core.utils.ExprUtils.simplify; import static org.junit.Assert.assertEquals; +import hu.bme.mit.theta.core.type.bvtype.BvExprs; +import hu.bme.mit.theta.core.type.bvtype.BvType; +import hu.bme.mit.theta.core.type.inttype.IntExprs; import org.junit.Test; import hu.bme.mit.theta.core.decl.ConstDecl; @@ -65,6 +70,8 @@ import hu.bme.mit.theta.core.type.inttype.IntType; import hu.bme.mit.theta.core.type.rattype.RatType; +import java.util.List; + public class ExprSimplifierTest { private final ConstDecl cx = Const("x", Bool()); @@ -74,6 +81,8 @@ public class ExprSimplifierTest { private final ConstDecl cb = Const("b", Int()); private final ConstDecl cc = Const("c", Int()); private final ConstDecl cd = Const("d", Rat()); + private final ConstDecl ce = Const("e", BvType(4, false)); + private final ConstDecl cf = Const("f", BvType(4, false)); private final Expr x = cx.getRef(); private final Expr y = cy.getRef(); @@ -82,6 +91,8 @@ public class ExprSimplifierTest { private final Expr b = cb.getRef(); private final Expr c = cc.getRef(); private final Expr d = cd.getRef(); + private final Expr e = ce.getRef(); + private final Expr f = cf.getRef(); // Boolean @@ -232,6 +243,18 @@ public void testIntToRat() { } } + @Test + public void testIntToBv() { + assertEquals( + Bv(new boolean[] {true, true, false, false}, false), + simplify(IntExprs.ToBv(Int(12), 4, false)) + ); + assertEquals( + Bv(new boolean[] {true, true, false, false}, true), + simplify(IntExprs.ToBv(Int(-4), 4, true)) + ); + } + @Test public void testIntAdd() { assertEquals(Int(6), simplify(Add(Int(1), Int(2), Int(3)))); @@ -336,6 +359,360 @@ public void testIntLt() { assertEquals(False(), simplify(Lt(a, a))); } + // Bitvectors + + @Test + public void testBvAdd() { + assertEquals( + Bv(new boolean[] {false, false, true, true}, false), + simplify(BvExprs.Add(List.of( + Bv(new boolean[] {false, false, true, false}, false), + Bv(new boolean[] {false, false, false, true}, false) + ))) + ); + assertEquals( + BvExprs.Add(List.of( + e, + Bv(new boolean[] {false, false, true, true}, false) + )), + simplify(BvExprs.Add(List.of( + Bv(new boolean[] {false, false, true, false}, false), + e, + Bv(new boolean[] {false, false, false, true}, false) + ))) + ); + } + + @Test + public void testBvSub() { + assertEquals( + Bv(new boolean[] {false, false, false, true}, false), + simplify(BvExprs.Sub( + Bv(new boolean[] {false, false, true, false}, false), + Bv(new boolean[] {false, false, false, true}, false) + )) + ); + assertEquals( + BvExprs.Sub( + e, + Bv(new boolean[] {false, false, true, true}, false) + ), + simplify(BvExprs.Sub( + e, + BvExprs.Add(List.of( + Bv(new boolean[] {false, false, true, false}, false), + Bv(new boolean[] {false, false, false, true}, false) + )) + )) + ); + } + + @Test + public void testBvNeg() { + assertEquals( + Bv(new boolean[] {false, false, false, true}, true), + simplify(BvExprs.Neg(Bv(new boolean[] {true, true, true, true}, true))) + ); + assertEquals( + Bv(new boolean[] {false, false, false, true}, true), + simplify(BvExprs.Neg(BvExprs.Neg(Bv(new boolean[] {false, false, false, true}, true)))) + ); + } + + @Test + public void testBvMul() { + assertEquals( + Bv(new boolean[] {false, true, true, false}, false), + simplify(BvExprs.Mul(List.of( + Bv(new boolean[] {false, false, true, true}, false), + Bv(new boolean[] {false, false, true, false}, false) + ))) + ); + assertEquals( + BvExprs.Mul(List.of( + Bv(new boolean[] {false, true, true, false}, false), + e + )), + simplify(BvExprs.Mul(List.of( + e, + Bv(new boolean[] {false, false, true, true}, false), + Bv(new boolean[] {false, false, true, false}, false) + ))) + ); + } + + @Test + public void testBvDiv() { + assertEquals( + Bv(new boolean[] {false, false, false, true}, false), + simplify(BvExprs.Div( + Bv(new boolean[] {false, true, false, false}, false), + Bv(new boolean[] {false, false, true, true}, false) + )) + ); + assertEquals( + Bv(new boolean[] {false, false, false, true}, false), + simplify(BvExprs.Div(e, e)) + ); + } + + @Test + public void testBvMod() { + assertEquals( + Bv(new boolean[] {false, false, false, true}, false), + simplify(BvExprs.Mod( + Bv(new boolean[] {false, true, false, false}, false), + Bv(new boolean[] {false, false, true, true}, false) + )) + ); + assertEquals( + Bv(new boolean[] {false, false, false, false}, false), + simplify(BvExprs.Mod(e, e)) + ); + } + + @Test + public void testBvRem() { + assertEquals( + Bv(new boolean[] {false, false, false, true}, false), + simplify(BvExprs.Rem( + Bv(new boolean[] {false, true, false, false}, false), + Bv(new boolean[] {false, false, true, true}, false) + )) + ); + assertEquals( + Bv(new boolean[] {false, false, false, false}, false), + simplify(BvExprs.Rem(e, e)) + ); + } + + @Test + public void testBvAnd() { + assertEquals( + Bv(new boolean[] {false, true, false, false}, false), + simplify(BvExprs.And(List.of( + Bv(new boolean[] {false, true, false, true}, false), + Bv(new boolean[] {false, true, true, false}, false) + ))) + ); + assertEquals( + BvExprs.And(List.of( + e, + Bv(new boolean[] {false, true, false, false}, false) + )), + simplify(BvExprs.And(List.of( + e, + Bv(new boolean[] {false, true, false, true}, false), + Bv(new boolean[] {false, true, true, false}, false) + ))) + ); + } + + @Test + public void testBvOr() { + assertEquals( + Bv(new boolean[] {false, true, true, true}, false), + simplify(BvExprs.Or(List.of( + Bv(new boolean[] {false, true, false, true}, false), + Bv(new boolean[] {false, true, true, false}, false) + ))) + ); + assertEquals( + BvExprs.Or(List.of( + e, + Bv(new boolean[] {false, true, true, true}, false) + )), + simplify(BvExprs.Or(List.of( + e, + Bv(new boolean[] {false, true, false, true}, false), + Bv(new boolean[] {false, true, true, false}, false) + ))) + ); + } + + @Test + public void testBvXor() { + assertEquals( + Bv(new boolean[] {false, false, true, true}, false), + simplify(BvExprs.Xor(List.of( + Bv(new boolean[] {false, true, false, true}, false), + Bv(new boolean[] {false, true, true, false}, false) + ))) + ); + assertEquals( + BvExprs.Xor(List.of( + e, + Bv(new boolean[] {false, false, true, true}, false) + )), + simplify(BvExprs.Xor(List.of( + e, + Bv(new boolean[] {false, true, false, true}, false), + Bv(new boolean[] {false, true, true, false}, false) + ))) + ); + } + + @Test + public void testBvNot() { + assertEquals( + Bv(new boolean[] {false, false, false, true}, true), + simplify(BvExprs.Not(Bv(new boolean[] {true, true, true, false}, true))) + ); + assertEquals( + Bv(new boolean[] {false, false, false, true}, true), + simplify(BvExprs.Not(BvExprs.Not(Bv(new boolean[] {false, false, false, true}, true)))) + ); + } + + @Test + public void testBvShift() { + assertEquals( + Bv(new boolean[] {false, true, false, false}, true), + simplify(BvExprs.ShiftLeft( + Bv(new boolean[] {false, false, false, true}, true), + Bv(new boolean[] {false, false, true, false}, true) + )) + ); + + assertEquals( + Bv(new boolean[] {false, false, false, true}, true), + simplify(BvExprs.ShiftRight( + Bv(new boolean[] {false, true, false, false}, true), + Bv(new boolean[] {false, false, true, false}, true) + )) + ); + + assertEquals( + Bv(new boolean[] {true, true, true, false}, true), + simplify(BvExprs.ShiftRight( + Bv(new boolean[] {true, true, false, false}, true), + Bv(new boolean[] {false, false, false, true}, true) + )) + ); + } + + @Test + public void testBvEq() { + assertEquals( + True(), + simplify(BvExprs.Eq( + Bv(new boolean[] {false, true, false, false}, false), + Bv(new boolean[] {false, true, false, false}, false) + )) + ); + assertEquals( + False(), + simplify(BvExprs.Eq( + Bv(new boolean[] {false, true, false, false}, false), + Bv(new boolean[] {false, true, false, true}, false) + )) + ); + } + + @Test + public void testBvNeq() { + assertEquals( + False(), + simplify(BvExprs.Neq( + Bv(new boolean[] {false, true, false, false}, false), + Bv(new boolean[] {false, true, false, false}, false) + )) + ); + assertEquals( + True(), + simplify(BvExprs.Neq( + Bv(new boolean[] {false, true, false, false}, false), + Bv(new boolean[] {false, true, false, true}, false) + )) + ); + } + + @Test + public void testBvGeq() { + assertEquals( + True(), + simplify(BvExprs.Geq( + Bv(new boolean[] {false, true, false, false}, false), + Bv(new boolean[] {false, false, true, false}, false) + )) + ); + assertEquals( + False(), + simplify(BvExprs.Geq( + Bv(new boolean[] {false, false, true, false}, false), + Bv(new boolean[] {false, true, false, true}, false) + )) + ); + } + + @Test + public void testBvGt() { + assertEquals( + True(), + simplify(BvExprs.Gt( + Bv(new boolean[] {false, true, false, false}, false), + Bv(new boolean[] {false, false, true, false}, false) + )) + ); + assertEquals( + False(), + simplify(BvExprs.Gt( + Bv(new boolean[] {false, false, true, false}, false), + Bv(new boolean[] {false, true, false, true}, false) + )) + ); + } + + @Test + public void testBvLeq() { + assertEquals( + False(), + simplify(BvExprs.Leq( + Bv(new boolean[] {false, true, false, false}, false), + Bv(new boolean[] {false, false, true, false}, false) + )) + ); + assertEquals( + True(), + simplify(BvExprs.Leq( + Bv(new boolean[] {false, false, true, false}, false), + Bv(new boolean[] {false, true, false, true}, false) + )) + ); + } + + @Test + public void testBvLt() { + assertEquals( + False(), + simplify(BvExprs.Lt( + Bv(new boolean[] {false, true, false, false}, false), + Bv(new boolean[] {false, false, true, false}, false) + )) + ); + assertEquals( + True(), + simplify(BvExprs.Lt( + Bv(new boolean[] {false, false, true, false}, false), + Bv(new boolean[] {false, true, false, true}, false) + )) + ); + } + + @Test + public void testBvToInt() { + assertEquals( + Int(12), + simplify(BvExprs.ToInt(Bv(new boolean[] {true, true, false, false}, false))) + ); + assertEquals( + Int(-4), + simplify(BvExprs.ToInt(Bv(new boolean[] {true, true, false, false}, true))) + ); + } + + // Others + @Test public void testRef() { final Valuation val = ImmutableValuation.builder().put(ca, Int(2)).build(); From 40ab08ce45e1dd14b1ecacb3dca9fe62656af935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Dobos-Kov=C3=A1cs?= Date: Thu, 2 Apr 2020 19:18:08 +0200 Subject: [PATCH 12/23] Refactor casting --- .../bme/mit/theta/cfa/dsl/CfaExpression.java | 6 +- .../mit/theta/core/type/bvtype/BvAddExpr.java | 13 +++- .../mit/theta/core/type/bvtype/BvAndExpr.java | 9 ++- .../mit/theta/core/type/bvtype/BvDivExpr.java | 7 +- .../mit/theta/core/type/bvtype/BvEqExpr.java | 8 +-- .../mit/theta/core/type/bvtype/BvGeqExpr.java | 7 +- .../mit/theta/core/type/bvtype/BvGtExpr.java | 7 +- .../mit/theta/core/type/bvtype/BvLeqExpr.java | 7 +- .../mit/theta/core/type/bvtype/BvLtExpr.java | 7 +- .../mit/theta/core/type/bvtype/BvModExpr.java | 7 +- .../mit/theta/core/type/bvtype/BvMulExpr.java | 8 ++- .../mit/theta/core/type/bvtype/BvNegExpr.java | 4 +- .../mit/theta/core/type/bvtype/BvNeqExpr.java | 8 +-- .../mit/theta/core/type/bvtype/BvNotExpr.java | 3 +- .../mit/theta/core/type/bvtype/BvOrExpr.java | 8 ++- .../mit/theta/core/type/bvtype/BvRemExpr.java | 7 +- .../core/type/bvtype/BvShiftLeftExpr.java | 7 +- .../core/type/bvtype/BvShiftRightExpr.java | 7 +- .../mit/theta/core/type/bvtype/BvSubExpr.java | 7 +- .../mit/theta/core/type/bvtype/BvXorExpr.java | 8 ++- .../mit/theta/core/utils/ExprSimplifier.java | 1 - .../bme/mit/theta/core/utils/TypeUtils.java | 49 ++++++++++++++ .../theta/solver/z3/Z3ExprTransformer.java | 67 +++++++++++-------- .../bme/mit/theta/solver/z3/Z3SolverTest.java | 6 +- 24 files changed, 181 insertions(+), 87 deletions(-) diff --git a/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java b/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java index 2c5805c833..eda695bbb6 100644 --- a/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java +++ b/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java @@ -343,7 +343,7 @@ public Expr visitBitwiseOrExpr(final BitwiseOrExprContext ctx) { switch (ctx.oper.getType()) { case BITWISE_OR: - return BvExprs.Or(leftOp, rightOp); + return BvExprs.Or(List.of(leftOp, rightOp)); default: throw new AssertionError(); } @@ -361,7 +361,7 @@ public Expr visitBitwiseXorExpr(final BitwiseXorExprContext ctx) { switch (ctx.oper.getType()) { case BITWISE_XOR: - return BvExprs.Xor(leftOp, rightOp); + return BvExprs.Xor(List.of(leftOp, rightOp)); default: throw new AssertionError(); } @@ -379,7 +379,7 @@ public Expr visitBitwiseAndExpr(final BitwiseAndExprContext ctx) { switch (ctx.oper.getType()) { case BITWISE_AND: - return BvExprs.And(leftOp, rightOp); + return BvExprs.And(List.of(leftOp, rightOp)); default: throw new AssertionError(); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java index 37df3445a9..496010b650 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java @@ -7,14 +7,20 @@ import hu.bme.mit.theta.core.type.inttype.IntLitExpr; import hu.bme.mit.theta.core.type.inttype.IntType; import hu.bme.mit.theta.core.utils.BvUtils; +import hu.bme.mit.theta.core.utils.TypeUtils; import java.math.BigInteger; +import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.ImmutableList.toImmutableList; import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; -import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.*; +import static java.util.stream.Collectors.*; public class BvAddExpr extends AddExpr { private static final int HASH_SEED = 6586; @@ -22,6 +28,7 @@ public class BvAddExpr extends AddExpr { private BvAddExpr(final Iterable> ops) { super(ops); + checkAllTypesEqual(ops); } public static BvAddExpr of(final Iterable> ops) { @@ -29,8 +36,8 @@ public static BvAddExpr of(final Iterable> ops) { } public static BvAddExpr create(final List> ops) { - checkArgument(!ops.isEmpty()); - return BvAddExpr.of(ops.stream().map(op -> cast(op, (BvType) ops.get(0).getType())).collect(toImmutableList())); + checkNotNull(ops); + return BvAddExpr.of(ops.stream().map(TypeUtils::castBv).collect(toImmutableList())); } @Override diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAndExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAndExpr.java index 9aa97b008b..ede86135e4 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAndExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAndExpr.java @@ -3,12 +3,14 @@ import hu.bme.mit.theta.core.model.Valuation; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.MultiaryExpr; +import hu.bme.mit.theta.core.utils.TypeUtils; import java.util.List; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.ImmutableList.toImmutableList; -import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.*; public class BvAndExpr extends MultiaryExpr { private static final int HASH_SEED = 9125; @@ -16,6 +18,7 @@ public class BvAndExpr extends MultiaryExpr { private BvAndExpr(final Iterable> ops) { super(ops); + checkAllTypesEqual(ops); } public static BvAndExpr of(final Iterable> ops) { @@ -23,8 +26,8 @@ public static BvAndExpr of(final Iterable> ops) { } public static BvAndExpr create(final List> ops) { - checkArgument(!ops.isEmpty()); - return BvAndExpr.of(ops.stream().map(op -> cast(op, (BvType) ops.get(0).getType())).collect(toImmutableList())); + checkNotNull(ops); + return BvAndExpr.of(ops.stream().map(TypeUtils::castBv).collect(toImmutableList())); } @Override diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java index 021f54831d..a2a720db40 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java @@ -8,7 +8,7 @@ import java.math.BigInteger; import static hu.bme.mit.theta.core.type.bvtype.BvExprs.Bv; -import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.*; public class BvDivExpr extends DivExpr { private static final int HASH_SEED = 9832; @@ -17,6 +17,7 @@ public class BvDivExpr extends DivExpr { private BvDivExpr(final Expr leftOp, final Expr rightOp) { super(leftOp, rightOp); + checkAllTypesEqual(leftOp, rightOp); } public static BvDivExpr of(final Expr leftOp, final Expr rightOp) { @@ -24,8 +25,8 @@ public static BvDivExpr of(final Expr leftOp, final Expr rightOp } public static BvDivExpr create(final Expr leftOp, final Expr rightOp) { - final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); - final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + final Expr newLeftOp = castBv(leftOp); + final Expr newRightOp = castBv(rightOp); return BvDivExpr.of(newLeftOp, newRightOp); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java index 902099b42a..16114f16ce 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java @@ -10,7 +10,7 @@ import static com.google.common.base.Preconditions.checkState; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; -import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.*; public class BvEqExpr extends EqExpr { @@ -19,6 +19,7 @@ public class BvEqExpr extends EqExpr { private BvEqExpr(final Expr leftOp, final Expr rightOp) { super(leftOp, rightOp); + checkAllTypesEqual(leftOp, rightOp); } public static BvEqExpr of(final Expr leftOp, final Expr rightOp) { @@ -26,9 +27,8 @@ public static BvEqExpr of(final Expr leftOp, final Expr rightOp) } public static BvEqExpr create(final Expr leftOp, final Expr rightOp) { - BvType bvType = (BvType) leftOp.getType(); - final Expr newLeftOp = cast(leftOp, bvType); - final Expr newRightOp = cast(rightOp, bvType); + final Expr newLeftOp = castBv(leftOp); + final Expr newRightOp = castBv(rightOp); return BvEqExpr.of(newLeftOp, newRightOp); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGeqExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGeqExpr.java index a2d30e89ea..e601ec5dc0 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGeqExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGeqExpr.java @@ -8,7 +8,7 @@ import hu.bme.mit.theta.core.type.booltype.BoolType; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; -import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.*; public class BvGeqExpr extends GeqExpr { @@ -17,6 +17,7 @@ public class BvGeqExpr extends GeqExpr { private BvGeqExpr(final Expr leftOp, final Expr rightOp) { super(leftOp, rightOp); + checkAllTypesEqual(leftOp, rightOp); } public static BvGeqExpr of(final Expr leftOp, final Expr rightOp) { @@ -24,8 +25,8 @@ public static BvGeqExpr of(final Expr leftOp, final Expr rightOp } public static BvGeqExpr create(final Expr leftOp, final Expr rightOp) { - final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); - final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + final Expr newLeftOp = castBv(leftOp); + final Expr newRightOp = castBv(rightOp); return BvGeqExpr.of(newLeftOp, newRightOp); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGtExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGtExpr.java index 364a472dad..3e120b8479 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGtExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGtExpr.java @@ -8,7 +8,7 @@ import hu.bme.mit.theta.core.type.booltype.BoolType; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; -import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.*; public class BvGtExpr extends GtExpr { @@ -17,6 +17,7 @@ public class BvGtExpr extends GtExpr { private BvGtExpr(final Expr leftOp, final Expr rightOp) { super(leftOp, rightOp); + checkAllTypesEqual(leftOp, rightOp); } public static BvGtExpr of(final Expr leftOp, final Expr rightOp) { @@ -24,8 +25,8 @@ public static BvGtExpr of(final Expr leftOp, final Expr rightOp) } public static BvGtExpr create(final Expr leftOp, final Expr rightOp) { - final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); - final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + final Expr newLeftOp = castBv(leftOp); + final Expr newRightOp = castBv(rightOp); return BvGtExpr.of(newLeftOp, newRightOp); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLeqExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLeqExpr.java index 9b988b869f..df82496b1f 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLeqExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLeqExpr.java @@ -8,7 +8,7 @@ import hu.bme.mit.theta.core.type.booltype.BoolType; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; -import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.*; public class BvLeqExpr extends LeqExpr { @@ -17,6 +17,7 @@ public class BvLeqExpr extends LeqExpr { private BvLeqExpr(final Expr leftOp, final Expr rightOp) { super(leftOp, rightOp); + checkAllTypesEqual(leftOp, rightOp); } public static BvLeqExpr of(final Expr leftOp, final Expr rightOp) { @@ -24,8 +25,8 @@ public static BvLeqExpr of(final Expr leftOp, final Expr rightOp } public static BvLeqExpr create(final Expr leftOp, final Expr rightOp) { - final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); - final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + final Expr newLeftOp = castBv(leftOp); + final Expr newRightOp = castBv(rightOp); return BvLeqExpr.of(newLeftOp, newRightOp); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLtExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLtExpr.java index cb4f8ad010..d2469e0015 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLtExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLtExpr.java @@ -7,7 +7,7 @@ import hu.bme.mit.theta.core.type.booltype.BoolType; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; -import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.*; public class BvLtExpr extends LtExpr { @@ -16,6 +16,7 @@ public class BvLtExpr extends LtExpr { private BvLtExpr(final Expr leftOp, final Expr rightOp) { super(leftOp, rightOp); + checkAllTypesEqual(leftOp, rightOp); } public static BvLtExpr of(final Expr leftOp, final Expr rightOp) { @@ -23,8 +24,8 @@ public static BvLtExpr of(final Expr leftOp, final Expr rightOp) } public static BvLtExpr create(final Expr leftOp, final Expr rightOp) { - final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); - final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + final Expr newLeftOp = castBv(leftOp); + final Expr newRightOp = castBv(rightOp); return BvLtExpr.of(newLeftOp, newRightOp); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvModExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvModExpr.java index c23218d7bf..04f5d8bc51 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvModExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvModExpr.java @@ -5,7 +5,7 @@ import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.abstracttype.ModExpr; -import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.*; public class BvModExpr extends ModExpr { @@ -14,6 +14,7 @@ public class BvModExpr extends ModExpr { private BvModExpr(final Expr leftOp, final Expr rightOp) { super(leftOp, rightOp); + checkAllTypesEqual(leftOp, rightOp); } public static BvModExpr of(final Expr leftOp, final Expr rightOp) { @@ -21,8 +22,8 @@ public static BvModExpr of(final Expr leftOp, final Expr rightOp } public static BvModExpr create(final Expr leftOp, final Expr rightOp) { - final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); - final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + final Expr newLeftOp = castBv(leftOp); + final Expr newRightOp = castBv(rightOp); return BvModExpr.of(newLeftOp, newRightOp); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java index 042a977dce..a1439b1054 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java @@ -4,14 +4,17 @@ import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.abstracttype.MulExpr; import hu.bme.mit.theta.core.utils.BvUtils; +import hu.bme.mit.theta.core.utils.TypeUtils; import java.math.BigInteger; import java.util.List; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.ImmutableList.toImmutableList; import static hu.bme.mit.theta.core.type.bvtype.BvExprs.Bv; import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.checkAllTypesEqual; public class BvMulExpr extends MulExpr { private static final int HASH_SEED = 9825; @@ -19,6 +22,7 @@ public class BvMulExpr extends MulExpr { private BvMulExpr(final Iterable> ops) { super(ops); + checkAllTypesEqual(ops); } public static BvMulExpr of(final Iterable> ops) { @@ -26,8 +30,8 @@ public static BvMulExpr of(final Iterable> ops) { } public static BvMulExpr create(final List> ops) { - checkArgument(!ops.isEmpty()); - return BvMulExpr.of(ops.stream().map(op -> cast(op, (BvType) ops.get(0).getType())).collect(toImmutableList())); + checkNotNull(ops); + return BvMulExpr.of(ops.stream().map(TypeUtils::castBv).collect(toImmutableList())); } @Override diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java index fde625a277..b2aa1546be 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java @@ -8,7 +8,7 @@ import java.math.BigInteger; import static com.google.common.base.Preconditions.checkArgument; -import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.*; public class BvNegExpr extends NegExpr { @@ -25,7 +25,7 @@ public static BvNegExpr of(final Expr op) { } public static BvNegExpr create(final Expr op) { - final Expr newOp = cast(op, (BvType) op.getType()); + final Expr newOp = castBv(op); return BvNegExpr.of(newOp); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java index 2c5261521f..6c563a7554 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java @@ -10,7 +10,7 @@ import static com.google.common.base.Preconditions.checkState; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; -import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.*; public class BvNeqExpr extends NeqExpr { private static final int HASH_SEED = 2488; @@ -18,6 +18,7 @@ public class BvNeqExpr extends NeqExpr { private BvNeqExpr(final Expr leftOp, final Expr rightOp) { super(leftOp, rightOp); + checkAllTypesEqual(leftOp, rightOp); } public static BvNeqExpr of(final Expr leftOp, final Expr rightOp) { @@ -25,9 +26,8 @@ public static BvNeqExpr of(final Expr leftOp, final Expr rightOp } public static BvNeqExpr create(final Expr leftOp, final Expr rightOp) { - BvType bvType = (BvType) leftOp.getType(); - final Expr newLeftOp = cast(leftOp, bvType); - final Expr newRightOp = cast(rightOp, bvType); + final Expr newLeftOp = castBv(leftOp); + final Expr newRightOp = castBv(rightOp); return BvNeqExpr.of(newLeftOp, newRightOp); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNotExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNotExpr.java index 0f26a7ff99..286802d1bc 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNotExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNotExpr.java @@ -5,6 +5,7 @@ import hu.bme.mit.theta.core.type.abstracttype.NegExpr; import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.castBv; public class BvNotExpr extends NegExpr { @@ -20,7 +21,7 @@ public static BvNotExpr of(final Expr op) { } public static BvNotExpr create(final Expr op) { - final Expr newOp = cast(op, (BvType) op.getType()); + final Expr newOp = castBv(op); return BvNotExpr.of(newOp); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvOrExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvOrExpr.java index af8665b6eb..9c0a79f6a2 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvOrExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvOrExpr.java @@ -4,12 +4,15 @@ import hu.bme.mit.theta.core.type.BinaryExpr; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.MultiaryExpr; +import hu.bme.mit.theta.core.utils.TypeUtils; import java.util.List; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.ImmutableList.toImmutableList; import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.checkAllTypesEqual; public class BvOrExpr extends MultiaryExpr { private static final int HASH_SEED = 2745; @@ -17,6 +20,7 @@ public class BvOrExpr extends MultiaryExpr { private BvOrExpr(final Iterable> ops) { super(ops); + checkAllTypesEqual(ops); } public static BvOrExpr of(final Iterable> ops) { @@ -24,8 +28,8 @@ public static BvOrExpr of(final Iterable> ops) { } public static BvOrExpr create(final List> ops) { - checkArgument(!ops.isEmpty()); - return BvOrExpr.of(ops.stream().map(op -> cast(op, (BvType) ops.get(0).getType())).collect(toImmutableList())); + checkNotNull(ops); + return BvOrExpr.of(ops.stream().map(TypeUtils::castBv).collect(toImmutableList())); } @Override diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvRemExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvRemExpr.java index 9fe45006d3..421366d36c 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvRemExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvRemExpr.java @@ -5,7 +5,7 @@ import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.abstracttype.RemExpr; -import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.*; public class BvRemExpr extends RemExpr { @@ -15,6 +15,7 @@ public class BvRemExpr extends RemExpr { private BvRemExpr(final Expr leftOp, final Expr rightOp) { super(leftOp, rightOp); + checkAllTypesEqual(leftOp, rightOp); } public static BvRemExpr of(final Expr leftOp, final Expr rightOp) { @@ -22,8 +23,8 @@ public static BvRemExpr of(final Expr leftOp, final Expr rightOp } public static BvRemExpr create(final Expr leftOp, final Expr rightOp) { - final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); - final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + final Expr newLeftOp = castBv(leftOp); + final Expr newRightOp = castBv(rightOp); return BvRemExpr.of(newLeftOp, newRightOp); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvShiftLeftExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvShiftLeftExpr.java index 36430880b2..cb922bed05 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvShiftLeftExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvShiftLeftExpr.java @@ -4,7 +4,7 @@ import hu.bme.mit.theta.core.type.BinaryExpr; import hu.bme.mit.theta.core.type.Expr; -import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.*; public class BvShiftLeftExpr extends BinaryExpr { private static final int HASH_SEED = 4288; @@ -12,6 +12,7 @@ public class BvShiftLeftExpr extends BinaryExpr { private BvShiftLeftExpr(final Expr leftOp, final Expr rightOp) { super(leftOp, rightOp); + checkAllTypesEqual(leftOp, rightOp); } public static BvShiftLeftExpr of(final Expr leftOp, final Expr rightOp) { @@ -19,8 +20,8 @@ public static BvShiftLeftExpr of(final Expr leftOp, final Expr r } public static BvShiftLeftExpr create(final Expr leftOp, final Expr rightOp) { - final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); - final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + final Expr newLeftOp = castBv(leftOp); + final Expr newRightOp = castBv(rightOp); return BvShiftLeftExpr.of(newLeftOp, newRightOp); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvShiftRightExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvShiftRightExpr.java index 80277fb0cf..d5230eb6c1 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvShiftRightExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvShiftRightExpr.java @@ -4,7 +4,7 @@ import hu.bme.mit.theta.core.type.BinaryExpr; import hu.bme.mit.theta.core.type.Expr; -import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.*; public class BvShiftRightExpr extends BinaryExpr { private static final int HASH_SEED = 965; @@ -12,6 +12,7 @@ public class BvShiftRightExpr extends BinaryExpr { private BvShiftRightExpr(final Expr leftOp, final Expr rightOp) { super(leftOp, rightOp); + checkAllTypesEqual(leftOp, rightOp); } public static BvShiftRightExpr of(final Expr leftOp, final Expr rightOp) { @@ -19,8 +20,8 @@ public static BvShiftRightExpr of(final Expr leftOp, final Expr } public static BvShiftRightExpr create(final Expr leftOp, final Expr rightOp) { - final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); - final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + final Expr newLeftOp = castBv(leftOp); + final Expr newRightOp = castBv(rightOp); return BvShiftRightExpr.of(newLeftOp, newRightOp); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java index c357b5ff90..5497fe7718 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java @@ -9,7 +9,7 @@ import java.math.BigInteger; import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; -import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.*; public class BvSubExpr extends SubExpr { @@ -18,6 +18,7 @@ public class BvSubExpr extends SubExpr { private BvSubExpr(final Expr leftOp, final Expr rightOp) { super(leftOp, rightOp); + checkAllTypesEqual(leftOp, rightOp); } public static BvSubExpr of(final Expr leftOp, final Expr rightOp) { @@ -25,8 +26,8 @@ public static BvSubExpr of(final Expr leftOp, final Expr rightOp } public static BvSubExpr create(final Expr leftOp, final Expr rightOp) { - final Expr newLeftOp = cast(leftOp, (BvType) leftOp.getType()); - final Expr newRightOp = cast(rightOp, (BvType) leftOp.getType()); + final Expr newLeftOp = castBv(leftOp); + final Expr newRightOp = castBv(rightOp); return BvSubExpr.of(newLeftOp, newRightOp); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvXorExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvXorExpr.java index af4b3ba809..b05b7174db 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvXorExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvXorExpr.java @@ -4,12 +4,15 @@ import hu.bme.mit.theta.core.type.BinaryExpr; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.MultiaryExpr; +import hu.bme.mit.theta.core.utils.TypeUtils; import java.util.List; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.ImmutableList.toImmutableList; import static hu.bme.mit.theta.core.utils.TypeUtils.cast; +import static hu.bme.mit.theta.core.utils.TypeUtils.checkAllTypesEqual; public class BvXorExpr extends MultiaryExpr { private static final int HASH_SEED = 9457; @@ -17,6 +20,7 @@ public class BvXorExpr extends MultiaryExpr { private BvXorExpr(final Iterable> ops) { super(ops); + checkAllTypesEqual(ops); } public static BvXorExpr of(final Iterable> ops) { @@ -24,8 +28,8 @@ public static BvXorExpr of(final Iterable> ops) { } public static BvXorExpr create(final List> ops) { - checkArgument(!ops.isEmpty()); - return BvXorExpr.of(ops.stream().map(op -> cast(op, (BvType) ops.get(0).getType())).collect(toImmutableList())); + checkNotNull(ops); + return BvXorExpr.of(ops.stream().map(TypeUtils::castBv).collect(toImmutableList())); } @Override diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java index 2d7d4cad54..38f4d04335 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java @@ -190,7 +190,6 @@ public final class ExprSimplifier { }) .build(); - ; private ExprSimplifier() { } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/TypeUtils.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/TypeUtils.java index 6c13f4338f..e44a61c94e 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/TypeUtils.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/TypeUtils.java @@ -15,6 +15,7 @@ */ package hu.bme.mit.theta.core.utils; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import hu.bme.mit.theta.core.decl.Decl; @@ -23,6 +24,9 @@ import hu.bme.mit.theta.core.type.Type; import hu.bme.mit.theta.core.type.bvtype.BvType; +import java.util.Iterator; +import java.util.List; + /** * Utility functions related to types. */ @@ -88,6 +92,12 @@ public static Expr cast(final Expr expr, final T type) { } } + /** + * Cast an expression to bitvector type. + * + * @param expr Original expression + * @return Casted expression + */ public static Expr castBv(final Expr expr) { checkNotNull(expr); @@ -99,4 +109,43 @@ public static Expr castBv(final Expr expr) { } } + /** + * Check if all the types of the operands equal + * + * @param ops The expressions + */ + public static void checkAllTypesEqual(final Iterable> ops) { + checkNotNull(ops); + + final Iterator> iterator = ops.iterator(); + checkArgument(iterator.hasNext(), "There must be at least one element"); + + final Expr first = iterator.next(); + while (iterator.hasNext()) { + final Expr nth = iterator.next(); + checkArgument(first.getType().equals(nth.getType()), "All types must equal"); + } + } + + /** + * Check if all the types of the operands equal + * + * @param op The expression + */ + public static void checkAllTypesEqual(final Expr op) { + checkNotNull(op); + } + + /** + * Check if all the types of the operands equal + * + * @param op1 The expression + * @param op2 The expression + */ + public static void checkAllTypesEqual(final Expr op1, final Expr op2) { + checkNotNull(op1); + checkNotNull(op2); + checkArgument(op1.getType().equals(op2.getType()), "All types must equal"); + } + } diff --git a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java index 147847c0c9..af475e1bbe 100644 --- a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java +++ b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java @@ -22,6 +22,7 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.ImmutableList; +import com.microsoft.z3.BoolExpr; import com.microsoft.z3.Context; import hu.bme.mit.theta.common.DispatchTable; @@ -307,14 +308,16 @@ private com.microsoft.z3.Expr transformXor(final XorExpr expr) { } private com.microsoft.z3.Expr transformAnd(final AndExpr expr) { - final com.microsoft.z3.BoolExpr[] opTerms = expr.getOps().stream().map(this::toTerm) - .toArray(size -> new com.microsoft.z3.BoolExpr[size]); + final com.microsoft.z3.BoolExpr[] opTerms = expr.getOps().stream() + .map(e -> (com.microsoft.z3.BoolExpr) toTerm(e)) + .toArray(BoolExpr[]::new); return context.mkAnd(opTerms); } private com.microsoft.z3.Expr transformOr(final OrExpr expr) { - final com.microsoft.z3.BoolExpr[] opTerms = expr.getOps().stream().map(this::toTerm) - .toArray(size -> new com.microsoft.z3.BoolExpr[size]); + final com.microsoft.z3.BoolExpr[] opTerms = expr.getOps().stream() + .map(e -> (com.microsoft.z3.BoolExpr) toTerm(e)) + .toArray(BoolExpr[]::new); return context.mkOr(opTerms); } @@ -367,8 +370,9 @@ private com.microsoft.z3.Expr transformRatLit(final RatLitExpr expr) { } private com.microsoft.z3.Expr transformRatAdd(final RatAddExpr expr) { - final com.microsoft.z3.ArithExpr[] opTerms = expr.getOps().stream().map(this::toTerm) - .toArray(size -> new com.microsoft.z3.ArithExpr[size]); + final com.microsoft.z3.ArithExpr[] opTerms = expr.getOps().stream() + .map(e -> (com.microsoft.z3.ArithExpr) toTerm(e)) + .toArray(com.microsoft.z3.ArithExpr[]::new); return context.mkAdd(opTerms); } @@ -384,8 +388,9 @@ private com.microsoft.z3.Expr transformRatNeg(final RatNegExpr expr) { } private com.microsoft.z3.Expr transformRatMul(final RatMulExpr expr) { - final com.microsoft.z3.ArithExpr[] opTerms = expr.getOps().stream().map(this::toTerm) - .toArray(size -> new com.microsoft.z3.ArithExpr[size]); + final com.microsoft.z3.ArithExpr[] opTerms = expr.getOps().stream() + .map(e -> (com.microsoft.z3.ArithExpr) toTerm(e)) + .toArray(com.microsoft.z3.ArithExpr[]::new); return context.mkMul(opTerms); } @@ -440,8 +445,9 @@ private com.microsoft.z3.Expr transformIntLit(final IntLitExpr expr) { } private com.microsoft.z3.Expr transformIntAdd(final IntAddExpr expr) { - final com.microsoft.z3.ArithExpr[] opTerms = expr.getOps().stream().map(this::toTerm) - .toArray(size -> new com.microsoft.z3.ArithExpr[size]); + final com.microsoft.z3.ArithExpr[] opTerms = expr.getOps().stream() + .map(e -> (com.microsoft.z3.ArithExpr) toTerm(e)) + .toArray(com.microsoft.z3.ArithExpr[]::new); return context.mkAdd(opTerms); } @@ -457,8 +463,9 @@ private com.microsoft.z3.Expr transformIntNeg(final IntNegExpr expr) { } private com.microsoft.z3.Expr transformIntMul(final IntMulExpr expr) { - final com.microsoft.z3.ArithExpr[] opTerms = expr.getOps().stream().map(this::toTerm) - .toArray(size -> new com.microsoft.z3.ArithExpr[size]); + final com.microsoft.z3.ArithExpr[] opTerms = expr.getOps().stream() + .map(e -> (com.microsoft.z3.ArithExpr) toTerm(e)) + .toArray(com.microsoft.z3.ArithExpr[]::new); return context.mkMul(opTerms); } @@ -547,8 +554,9 @@ private com.microsoft.z3.Expr transformBvNeq(final BvNeqExpr expr) { } private com.microsoft.z3.Expr transformBvAdd(final BvAddExpr expr) { - final com.microsoft.z3.BitVecExpr[] opTerms = expr.getOps().stream().map(this::toTerm) - .toArray(com.microsoft.z3.BitVecExpr[]::new); + final com.microsoft.z3.BitVecExpr[] opTerms = expr.getOps().stream() + .map(e-> (com.microsoft.z3.BitVecExpr) toTerm(e)) + .toArray(com.microsoft.z3.BitVecExpr[]::new); return Stream.of(opTerms).skip(1).reduce(opTerms[0], context::mkBVAdd); } @@ -565,8 +573,9 @@ private com.microsoft.z3.Expr transformBvNeg(final BvNegExpr expr) { } private com.microsoft.z3.Expr transformBvMul(final BvMulExpr expr) { - final com.microsoft.z3.BitVecExpr[] opTerms = expr.getOps().stream().map(this::toTerm) - .toArray(com.microsoft.z3.BitVecExpr[]::new); + final com.microsoft.z3.BitVecExpr[] opTerms = expr.getOps().stream() + .map(e-> (com.microsoft.z3.BitVecExpr) toTerm(e)) + .toArray(com.microsoft.z3.BitVecExpr[]::new); return Stream.of(opTerms).skip(1).reduce(opTerms[0], context::mkBVMul); } @@ -608,24 +617,27 @@ private com.microsoft.z3.Expr transformBvRem(final BvRemExpr expr) { } private com.microsoft.z3.Expr transformBvAnd(final BvAndExpr expr) { - final com.microsoft.z3.BitVecExpr leftOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getLeftOp()); - final com.microsoft.z3.BitVecExpr rightOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getRightOp()); + final com.microsoft.z3.BitVecExpr[] opTerms = expr.getOps().stream() + .map(e-> (com.microsoft.z3.BitVecExpr) toTerm(e)) + .toArray(com.microsoft.z3.BitVecExpr[]::new); - return context.mkBVAND(leftOpTerm, rightOpTerm); + return Stream.of(opTerms).skip(1).reduce(opTerms[0], context::mkBVAND); } private com.microsoft.z3.Expr transformBvOr(final BvOrExpr expr) { - final com.microsoft.z3.BitVecExpr leftOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getLeftOp()); - final com.microsoft.z3.BitVecExpr rightOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getRightOp()); + final com.microsoft.z3.BitVecExpr[] opTerms = expr.getOps().stream() + .map(e-> (com.microsoft.z3.BitVecExpr) toTerm(e)) + .toArray(com.microsoft.z3.BitVecExpr[]::new); - return context.mkBVOR(leftOpTerm, rightOpTerm); + return Stream.of(opTerms).skip(1).reduce(opTerms[0], context::mkBVOR); } private com.microsoft.z3.Expr transformBvXor(final BvXorExpr expr) { - final com.microsoft.z3.BitVecExpr leftOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getLeftOp()); - final com.microsoft.z3.BitVecExpr rightOpTerm = (com.microsoft.z3.BitVecExpr) toTerm(expr.getRightOp()); + final com.microsoft.z3.BitVecExpr[] opTerms = expr.getOps().stream() + .map(e-> (com.microsoft.z3.BitVecExpr) toTerm(e)) + .toArray(com.microsoft.z3.BitVecExpr[]::new); - return context.mkBVXOR(leftOpTerm, rightOpTerm); + return Stream.of(opTerms).skip(1).reduce(opTerms[0], context::mkBVXOR); } private com.microsoft.z3.Expr transformBvNot(final BvNotExpr expr) { @@ -746,8 +758,9 @@ private com.microsoft.z3.Expr transformFuncApp(final FuncAppExpr expr) { final Decl decl = ref.getDecl(); final com.microsoft.z3.FuncDecl funcDecl = transformer.toSymbol(decl); final List> args = funcAndArgs.get2(); - final com.microsoft.z3.Expr[] argTerms = args.stream().map(this::toTerm) - .toArray(size -> new com.microsoft.z3.Expr[size]); + final com.microsoft.z3.Expr[] argTerms = args.stream() + .map(this::toTerm) + .toArray(com.microsoft.z3.Expr[]::new); return context.mkApp(funcDecl, argTerms); } else { throw new UnsupportedOperationException("Higher order functions are not supported: " + func); diff --git a/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java b/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java index d08106a993..8a2ce1fe04 100644 --- a/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java +++ b/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java @@ -296,7 +296,7 @@ public void testBV9() { solver.push(); solver.add(BvExprs.Eq(cy.getRef(), Bv(new boolean[] {false, true, false, false}, false))); - solver.add(BvExprs.Eq(BvExprs.Or(cx.getRef(), cy.getRef()), Bv(new boolean[] {true, true, false, false}, false))); + solver.add(BvExprs.Eq(BvExprs.Or(List.of(cx.getRef(), cy.getRef())), Bv(new boolean[] {true, true, false, false}, false))); SolverStatus status = solver.check(); assertTrue(status.isSat()); @@ -318,7 +318,7 @@ public void testBV10() { solver.push(); solver.add(BvExprs.Eq(cy.getRef(), Bv(new boolean[] {false, true, false, false}, false))); - solver.add(BvExprs.Eq(BvExprs.And(cx.getRef(), cy.getRef()), Bv(new boolean[] {false, true, false, false}, false))); + solver.add(BvExprs.Eq(BvExprs.And(List.of(cx.getRef(), cy.getRef())), Bv(new boolean[] {false, true, false, false}, false))); SolverStatus status = solver.check(); assertTrue(status.isSat()); @@ -340,7 +340,7 @@ public void testBV11() { solver.push(); solver.add(BvExprs.Eq(cy.getRef(), Bv(new boolean[] {false, true, false, false}, false))); - solver.add(BvExprs.Eq(BvExprs.Xor(cx.getRef(), cy.getRef()), Bv(new boolean[] {false, true, false, false}, false))); + solver.add(BvExprs.Eq(BvExprs.Xor(List.of(cx.getRef(), cy.getRef())), Bv(new boolean[] {false, true, false, false}, false))); SolverStatus status = solver.check(); assertTrue(status.isSat()); From 4b9fb19f8e2aa75c7b62c67611eec3b7f6c38429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Dobos-Kov=C3=A1cs?= Date: Thu, 2 Apr 2020 19:24:25 +0200 Subject: [PATCH 13/23] Cleanup code --- .../hu/bme/mit/theta/cfa/dsl/CfaExpression.java | 3 --- .../bme/mit/theta/core/type/bvtype/BvAddExpr.java | 13 +------------ .../bme/mit/theta/core/type/bvtype/BvAndExpr.java | 3 +-- .../bme/mit/theta/core/type/bvtype/BvDivExpr.java | 7 ++----- .../hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java | 6 ++---- .../hu/bme/mit/theta/core/type/bvtype/BvExprs.java | 3 --- .../bme/mit/theta/core/type/bvtype/BvGeqExpr.java | 4 ++-- .../hu/bme/mit/theta/core/type/bvtype/BvGtExpr.java | 4 ++-- .../bme/mit/theta/core/type/bvtype/BvLeqExpr.java | 4 ++-- .../bme/mit/theta/core/type/bvtype/BvModExpr.java | 4 ++-- .../bme/mit/theta/core/type/bvtype/BvMulExpr.java | 5 ----- .../bme/mit/theta/core/type/bvtype/BvNegExpr.java | 5 +---- .../bme/mit/theta/core/type/bvtype/BvNeqExpr.java | 6 ++---- .../bme/mit/theta/core/type/bvtype/BvNotExpr.java | 1 - .../hu/bme/mit/theta/core/type/bvtype/BvOrExpr.java | 3 --- .../bme/mit/theta/core/type/bvtype/BvRemExpr.java | 4 ++-- .../bme/mit/theta/core/type/bvtype/BvSubExpr.java | 8 ++------ .../hu/bme/mit/theta/core/type/bvtype/BvType.java | 2 -- .../bme/mit/theta/core/type/bvtype/BvXorExpr.java | 3 --- 19 files changed, 21 insertions(+), 67 deletions(-) diff --git a/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java b/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java index eda695bbb6..ef8f2a7f0a 100644 --- a/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java +++ b/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java @@ -101,9 +101,6 @@ import hu.bme.mit.theta.core.type.booltype.TrueExpr; import hu.bme.mit.theta.core.type.functype.FuncExprs; import hu.bme.mit.theta.core.type.inttype.IntLitExpr; -import hu.bme.mit.theta.core.type.inttype.IntType; -import hu.bme.mit.theta.core.type.inttype.IntModExpr; -import hu.bme.mit.theta.core.type.inttype.IntRemExpr; import hu.bme.mit.theta.core.type.rattype.RatLitExpr; import hu.bme.mit.theta.core.utils.TypeUtils; diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java index 496010b650..d67d3eac73 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAddExpr.java @@ -3,24 +3,13 @@ import hu.bme.mit.theta.core.model.Valuation; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.abstracttype.AddExpr; -import hu.bme.mit.theta.core.type.inttype.IntAddExpr; -import hu.bme.mit.theta.core.type.inttype.IntLitExpr; -import hu.bme.mit.theta.core.type.inttype.IntType; -import hu.bme.mit.theta.core.utils.BvUtils; import hu.bme.mit.theta.core.utils.TypeUtils; -import java.math.BigInteger; -import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; -import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.ImmutableList.toImmutableList; -import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; -import static hu.bme.mit.theta.core.utils.TypeUtils.*; -import static java.util.stream.Collectors.*; +import static hu.bme.mit.theta.core.utils.TypeUtils.checkAllTypesEqual; public class BvAddExpr extends AddExpr { private static final int HASH_SEED = 6586; diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAndExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAndExpr.java index ede86135e4..59654c8a00 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAndExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvAndExpr.java @@ -7,10 +7,9 @@ import java.util.List; -import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.ImmutableList.toImmutableList; -import static hu.bme.mit.theta.core.utils.TypeUtils.*; +import static hu.bme.mit.theta.core.utils.TypeUtils.checkAllTypesEqual; public class BvAndExpr extends MultiaryExpr { private static final int HASH_SEED = 9125; diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java index a2a720db40..fc6d852c8d 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvDivExpr.java @@ -3,12 +3,9 @@ import hu.bme.mit.theta.core.model.Valuation; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.abstracttype.DivExpr; -import hu.bme.mit.theta.core.utils.BvUtils; -import java.math.BigInteger; - -import static hu.bme.mit.theta.core.type.bvtype.BvExprs.Bv; -import static hu.bme.mit.theta.core.utils.TypeUtils.*; +import static hu.bme.mit.theta.core.utils.TypeUtils.castBv; +import static hu.bme.mit.theta.core.utils.TypeUtils.checkAllTypesEqual; public class BvDivExpr extends DivExpr { private static final int HASH_SEED = 9832; diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java index 16114f16ce..31b181fc07 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvEqExpr.java @@ -6,11 +6,9 @@ import hu.bme.mit.theta.core.type.booltype.BoolLitExpr; import hu.bme.mit.theta.core.type.booltype.BoolType; -import java.util.Arrays; - -import static com.google.common.base.Preconditions.checkState; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; -import static hu.bme.mit.theta.core.utils.TypeUtils.*; +import static hu.bme.mit.theta.core.utils.TypeUtils.castBv; +import static hu.bme.mit.theta.core.utils.TypeUtils.checkAllTypesEqual; public class BvEqExpr extends EqExpr { diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java index 8ae7fbe9da..d801533402 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvExprs.java @@ -1,9 +1,6 @@ package hu.bme.mit.theta.core.type.bvtype; import hu.bme.mit.theta.core.type.Expr; -import hu.bme.mit.theta.core.type.inttype.IntNegExpr; -import hu.bme.mit.theta.core.type.inttype.IntSubExpr; -import hu.bme.mit.theta.core.type.inttype.IntType; import java.util.List; diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGeqExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGeqExpr.java index e601ec5dc0..6301fc8cd1 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGeqExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGeqExpr.java @@ -4,11 +4,11 @@ import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.LitExpr; import hu.bme.mit.theta.core.type.abstracttype.GeqExpr; -import hu.bme.mit.theta.core.type.abstracttype.LtExpr; import hu.bme.mit.theta.core.type.booltype.BoolType; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; -import static hu.bme.mit.theta.core.utils.TypeUtils.*; +import static hu.bme.mit.theta.core.utils.TypeUtils.castBv; +import static hu.bme.mit.theta.core.utils.TypeUtils.checkAllTypesEqual; public class BvGeqExpr extends GeqExpr { diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGtExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGtExpr.java index 3e120b8479..5bc6d3f310 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGtExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvGtExpr.java @@ -4,11 +4,11 @@ import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.LitExpr; import hu.bme.mit.theta.core.type.abstracttype.GtExpr; -import hu.bme.mit.theta.core.type.abstracttype.LtExpr; import hu.bme.mit.theta.core.type.booltype.BoolType; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; -import static hu.bme.mit.theta.core.utils.TypeUtils.*; +import static hu.bme.mit.theta.core.utils.TypeUtils.castBv; +import static hu.bme.mit.theta.core.utils.TypeUtils.checkAllTypesEqual; public class BvGtExpr extends GtExpr { diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLeqExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLeqExpr.java index df82496b1f..ab673d62f4 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLeqExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLeqExpr.java @@ -4,11 +4,11 @@ import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.LitExpr; import hu.bme.mit.theta.core.type.abstracttype.LeqExpr; -import hu.bme.mit.theta.core.type.abstracttype.LtExpr; import hu.bme.mit.theta.core.type.booltype.BoolType; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; -import static hu.bme.mit.theta.core.utils.TypeUtils.*; +import static hu.bme.mit.theta.core.utils.TypeUtils.castBv; +import static hu.bme.mit.theta.core.utils.TypeUtils.checkAllTypesEqual; public class BvLeqExpr extends LeqExpr { diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvModExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvModExpr.java index 04f5d8bc51..4efa67d9d8 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvModExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvModExpr.java @@ -1,11 +1,11 @@ package hu.bme.mit.theta.core.type.bvtype; import hu.bme.mit.theta.core.model.Valuation; -import hu.bme.mit.theta.core.type.BinaryExpr; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.abstracttype.ModExpr; -import static hu.bme.mit.theta.core.utils.TypeUtils.*; +import static hu.bme.mit.theta.core.utils.TypeUtils.castBv; +import static hu.bme.mit.theta.core.utils.TypeUtils.checkAllTypesEqual; public class BvModExpr extends ModExpr { diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java index a1439b1054..02e84bd910 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvMulExpr.java @@ -3,17 +3,12 @@ import hu.bme.mit.theta.core.model.Valuation; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.abstracttype.MulExpr; -import hu.bme.mit.theta.core.utils.BvUtils; import hu.bme.mit.theta.core.utils.TypeUtils; -import java.math.BigInteger; import java.util.List; -import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.ImmutableList.toImmutableList; -import static hu.bme.mit.theta.core.type.bvtype.BvExprs.Bv; -import static hu.bme.mit.theta.core.utils.TypeUtils.cast; import static hu.bme.mit.theta.core.utils.TypeUtils.checkAllTypesEqual; public class BvMulExpr extends MulExpr { diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java index b2aa1546be..cc436c1413 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNegExpr.java @@ -3,12 +3,9 @@ import hu.bme.mit.theta.core.model.Valuation; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.abstracttype.NegExpr; -import hu.bme.mit.theta.core.utils.BvUtils; - -import java.math.BigInteger; import static com.google.common.base.Preconditions.checkArgument; -import static hu.bme.mit.theta.core.utils.TypeUtils.*; +import static hu.bme.mit.theta.core.utils.TypeUtils.castBv; public class BvNegExpr extends NegExpr { diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java index 6c563a7554..babfb53826 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNeqExpr.java @@ -6,11 +6,9 @@ import hu.bme.mit.theta.core.type.booltype.BoolLitExpr; import hu.bme.mit.theta.core.type.booltype.BoolType; -import java.util.Arrays; - -import static com.google.common.base.Preconditions.checkState; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; -import static hu.bme.mit.theta.core.utils.TypeUtils.*; +import static hu.bme.mit.theta.core.utils.TypeUtils.castBv; +import static hu.bme.mit.theta.core.utils.TypeUtils.checkAllTypesEqual; public class BvNeqExpr extends NeqExpr { private static final int HASH_SEED = 2488; diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNotExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNotExpr.java index 286802d1bc..f1d42f3562 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNotExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvNotExpr.java @@ -4,7 +4,6 @@ import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.abstracttype.NegExpr; -import static hu.bme.mit.theta.core.utils.TypeUtils.cast; import static hu.bme.mit.theta.core.utils.TypeUtils.castBv; public class BvNotExpr extends NegExpr { diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvOrExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvOrExpr.java index 9c0a79f6a2..05659b1e53 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvOrExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvOrExpr.java @@ -1,17 +1,14 @@ package hu.bme.mit.theta.core.type.bvtype; import hu.bme.mit.theta.core.model.Valuation; -import hu.bme.mit.theta.core.type.BinaryExpr; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.MultiaryExpr; import hu.bme.mit.theta.core.utils.TypeUtils; import java.util.List; -import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.ImmutableList.toImmutableList; -import static hu.bme.mit.theta.core.utils.TypeUtils.cast; import static hu.bme.mit.theta.core.utils.TypeUtils.checkAllTypesEqual; public class BvOrExpr extends MultiaryExpr { diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvRemExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvRemExpr.java index 421366d36c..cefa7aac29 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvRemExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvRemExpr.java @@ -1,11 +1,11 @@ package hu.bme.mit.theta.core.type.bvtype; import hu.bme.mit.theta.core.model.Valuation; -import hu.bme.mit.theta.core.type.BinaryExpr; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.abstracttype.RemExpr; -import static hu.bme.mit.theta.core.utils.TypeUtils.*; +import static hu.bme.mit.theta.core.utils.TypeUtils.castBv; +import static hu.bme.mit.theta.core.utils.TypeUtils.checkAllTypesEqual; public class BvRemExpr extends RemExpr { diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java index 5497fe7718..ac87b2622e 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvSubExpr.java @@ -3,13 +3,9 @@ import hu.bme.mit.theta.core.model.Valuation; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.abstracttype.SubExpr; -import hu.bme.mit.theta.core.type.inttype.IntLitExpr; -import hu.bme.mit.theta.core.utils.BvUtils; -import java.math.BigInteger; - -import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; -import static hu.bme.mit.theta.core.utils.TypeUtils.*; +import static hu.bme.mit.theta.core.utils.TypeUtils.castBv; +import static hu.bme.mit.theta.core.utils.TypeUtils.checkAllTypesEqual; public class BvSubExpr extends SubExpr { diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java index f5bb76c963..806fa9928c 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java @@ -4,9 +4,7 @@ import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.Type; import hu.bme.mit.theta.core.type.abstracttype.*; -import hu.bme.mit.theta.core.type.inttype.IntExprs; import hu.bme.mit.theta.core.type.inttype.IntType; -import hu.bme.mit.theta.core.type.rattype.RatType; import static com.google.common.base.Preconditions.checkArgument; diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvXorExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvXorExpr.java index b05b7174db..12998974f8 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvXorExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvXorExpr.java @@ -1,17 +1,14 @@ package hu.bme.mit.theta.core.type.bvtype; import hu.bme.mit.theta.core.model.Valuation; -import hu.bme.mit.theta.core.type.BinaryExpr; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.MultiaryExpr; import hu.bme.mit.theta.core.utils.TypeUtils; import java.util.List; -import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.ImmutableList.toImmutableList; -import static hu.bme.mit.theta.core.utils.TypeUtils.cast; import static hu.bme.mit.theta.core.utils.TypeUtils.checkAllTypesEqual; public class BvXorExpr extends MultiaryExpr { From df2f882dfd4ec7d196dbb85117bc9f50eb6213cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Dobos-Kov=C3=A1cs?= Date: Thu, 2 Apr 2020 19:32:13 +0200 Subject: [PATCH 14/23] Migrate CfaDsl changes to CoreDsl --- .../mit/theta/cfa/dsl/CfaDslManagerTest.java | 2 +- subprojects/core/src/main/antlr/CoreDsl.g4 | 85 ++++++++++++++++++- 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java b/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java index 07913dad47..d10ead8ad4 100644 --- a/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java +++ b/subprojects/cfa/src/test/java/hu/bme/mit/theta/cfa/dsl/CfaDslManagerTest.java @@ -58,7 +58,7 @@ public static Collection data() { {"/counter5_true.cfa", 1, 6, 6, 6}, - //{"/bv.cfa", 1, 6, 6, 6} + {"/bv.cfa", 1, 6, 6, 6}, {"/bv2.cfa", 1, 6, 6, 6} diff --git a/subprojects/core/src/main/antlr/CoreDsl.g4 b/subprojects/core/src/main/antlr/CoreDsl.g4 index f87c4e5a4d..d742f6400e 100644 --- a/subprojects/core/src/main/antlr/CoreDsl.g4 +++ b/subprojects/core/src/main/antlr/CoreDsl.g4 @@ -32,6 +32,7 @@ type: boolType | ratType | funcType | arrayType + | bvType ; typeList @@ -58,6 +59,19 @@ arrayType : LBRACK indexTypes=typeList RBRACK RARROW elemType=type ; +bvType + : ubvType + | sbvType + ; + +ubvType + : UBVTYPE LBRACK size=INT RBRACK + ; + +sbvType + : SBVTYPE LBRACK size=INT RBRACK + ; + BOOLTYPE : 'bool' ; @@ -70,6 +84,18 @@ RATTYPE : 'rat' ; +UBVTYPE + : 'bv' + | 'bitvec' + | 'ubv' + | 'ubitvec' + ; + +SBVTYPE + : 'sbv' + | 'sbitvec' + ; + // E X P R E S S I O N S expr: funcLitExpr @@ -129,9 +155,25 @@ equalityExpr ; relationExpr - : leftOp=additiveExpr (oper=(LT | LEQ | GT | GEQ) rightOp=additiveExpr)? + : leftOp=bitwiseOrExpr (oper=(LT | LEQ | GT | GEQ) rightOp=bitwiseOrExpr)? ; +bitwiseOrExpr + : leftOp=bitwiseXorExpr (oper=BITWISE_OR rightOp=bitwiseXorExpr)? + ; + +bitwiseXorExpr + : leftOp=bitwiseAndExpr (oper=BITWISE_XOR rightOp=bitwiseAndExpr)? + ; + +bitwiseAndExpr + : leftOp=bitwiseShiftExpr (oper=BITWISE_AND rightOp=bitwiseShiftExpr)? + ; + +bitwiseShiftExpr + : leftOp=additiveExpr (oper=(BITWISE_SHIFT_LEFT | BITWISE_SHIFT_RIGHT) rightOp=additiveExpr)? + ; + additiveExpr : ops+=multiplicativeExpr (opers+=(PLUS | MINUS) ops+=multiplicativeExpr)* ; @@ -141,10 +183,15 @@ multiplicativeExpr ; negExpr - : accessorExpr + : bitwiseNotExpr | MINUS op=negExpr ; +bitwiseNotExpr + : accessorExpr + | BITWISE_NOT op=bitwiseNotExpr + ; + accessorExpr : op=primaryExpr (accesses+=access)* ; @@ -172,6 +219,7 @@ primaryExpr | falseExpr | intLitExpr | ratLitExpr + | bvLitExpr | idExpr | parenExpr ; @@ -192,6 +240,10 @@ ratLitExpr : num=INT PERCENT denom=INT ; +bvLitExpr + : bv=BV + ; + idExpr : id=ID ; @@ -276,6 +328,30 @@ PERCENT : '%' ; +BITWISE_OR + : '|' + ; + +BITWISE_XOR + : '^' + ; + +BITWISE_AND + : '&' + ; + +BITWISE_SHIFT_LEFT + : LT LT + ; + +BITWISE_SHIFT_RIGHT + : GT GT + ; + +BITWISE_NOT + : '~' + ; + TRUE: 'true' ; @@ -322,6 +398,11 @@ ASSUME // B A S I C T O K E N S +BV : NAT '\'b' ('s'|'u')? [0-1]+ + | NAT '\'d' ('s'|'u')? INT + | NAT '\'x' ('s'|'u')? [0-9a-fA-F]+ + ; + INT : SIGN? NAT ; From 3f96f6a3714b9965f197a2e0e571cc6ec2a91417 Mon Sep 17 00:00:00 2001 From: as3810t Date: Sun, 31 May 2020 20:16:05 +0200 Subject: [PATCH 15/23] Create bitvectors.md --- subprojects/cfa/doc/bitvectors.md | 121 ++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 subprojects/cfa/doc/bitvectors.md diff --git a/subprojects/cfa/doc/bitvectors.md b/subprojects/cfa/doc/bitvectors.md new file mode 100644 index 0000000000..02a32ba7a5 --- /dev/null +++ b/subprojects/cfa/doc/bitvectors.md @@ -0,0 +1,121 @@ +# Bitvector support in Theta + +As of now, Theta has basic bitvector support for the CFA formalism. + +## Overview + +In Theta, every bitvector has a length, and is either signed or unsigned. It follows, that the range of every bitvector has a size of 2n. There are different operations that are available for bitvectors. It is important to note, that only operations between bitvectors with the same size and signedness are valid. + +Bitvectors have n bits. If the bitvector is unsigned then the values of the bits come from the binary representation of the underlying number. However, if the bitvector is signed then the values of the bits come from the two's complement representation of the underlying number. + +## Declaring bitvector variables + +To declare a bitvector variable, one has to specify the size and the signedness. + +``` +var x1 : bv[4] // Unsigned 4-bit-long bitvector +var x2 : bitvec[5] // Unsigned 5-bit-long bitvector + +var u1 : ubv[4] // Unsigned 4-bit-long bitvector +var u2 : ubitvec[6] // Unsigned 6-bit-long bitvector + +var s1 : sbv[4] // Signed 4-bit-long bitvector +var s2 : sbitvec[7] // Signed 7-bit-long bitvector + +``` + +## Bitvector literals + +There is a new literal, the bitvector literal that can be used to create bitvectors. Each literal defines the size and signedness of the literal. Moreover, eah literal can be entered using three different formats: + +- The bitwise precise binary form +- The bitwise precise hexadecimal form +- And the non-bitwise-precise, although user-friendly decimal form + +The two bitwise precise forms specify the value for all bits directly. These are useful for unsigned bitvectors, where there is no two's complement behavior (e.g. bitfields). + +``` +4'b0010 // Unsiged 4-bit-long bitvector literal (binary form) +8'xAF // Unsiged 4-bit-long bitvector literal (hexadecimal form) + +4'bu0010 // Unsiged 4-bit-long bitvector literal (binary form) +8'xuAF // Unsiged 4-bit-long bitvector literal (hexadecimal form) + +4'bs0010 // Signed 4-bit-long bitvector literal (binary form, not recommended) +8'xsAF // Signed 4-bit-long bitvector literal (hexadecimal form, not recommended) +``` + +The non-bitwise-precise decimal form can be used to create bitvectors that are based on numbers. Thsi form is recommended for signed bitvectors, or unsigned bitvectors that are not bitfields. + +``` +4'd10 // Unsigned 4-bit-long bitvector literal (decimal form) + +4'du10 // Unsigned 4-bit-long bitvector literal (decimal form) + +4'ds5 // Signed 4-bit-long bitvector literal (decimal form, positive value) +4'ds-5 // Signed 4-bit-long bitvector literal (decimal form, negative value) +``` + +## Operations on bitvectors + +The following operations are defined on bitvectors. As a general rule, every binary operation requires the bitvector on the left hand side and the bitvector on the right hand side to have the same size and signedness. + +The operators and their precedence are based on the [operators in C langauge](https://en.cppreference.com/w/c/language/operator_precedence). + +### Basic arithmetic operations + +These operations perform basic arithmetic operations on bitvectors. These operations require that the bitvector on the left hand side and the bitvector on the right hand side have the same size and signedness. These operations overflow! + +- **Addition:** Adds two bitvectors; `a + b` +- **Subtraction:** Subtracts a from b; `a - b` +- **Multiplication:** Multiplies two bitvectors; `a * b` +- **Integer division:** Divides two bitvectors, and takes the integer part of the result; `a / b` +- **Modulo:** Calculates (a mod b); `a mod b` +- **Remainder:** Calculates the remainder of a / b; `a rem b` +- **Negate:** Negates the value of a (only valid for signed bitvectors); `-a` + +### Bitvector specific operations + +These operations are specific to bitvectors only. These operations require that the bitvector on the left hand side and the bitvector on the right hand side have the same size and signedness. For the exact semantics check out the respective operators in C. These operations overflow! + +- **Bitwise and**: Ands two bitvectors; `a & b` +- **Bitwise or**: Ors two bitvectors; `a | b` +- **Bitwise xor**: XORs two bitvectors; `a ^ b` +- **Bitwise shift left**: Shifts a to left with b; `a << b` +- **Bitwise shift right**: Shifts a to right with b; `a >> b` +- **Bitwise not:** Negates all the bits in bitvectors; `~a` + +### Relational operations + +These operations encode relational operations between bitvectors. These operations require that the bitvector on the left hand side and the bitvector on the right hand side have the same size and signedness. + +- **Equality**: Checks if a equals to b; `a = b` +- **Non-equality**: Checks if a does not equal to b; `a /= b` +- **Greater than or equals to**: Checks if a is greater than or equals to b; `a >= b` +- **Greater than**: Checks if a is greater than b; `a > b` +- **Less than or equals to**: Checks if a is less than or equals to b; `a <= b` +- **Less than**: Checks if a is less than b; `a < b` + +### Conversion "operations" + +Bitvectors can be converted to integers, and vice-versa. However, since integers can have an arbitrily huge value, should that value be impossible to be represented in the bitvectors range, an exception will be thrown. So procede with caution! + +There is no explicit conversion operator, however, the assignment statement converts between the two types. + +``` +var bv1 : bv[4] +var i1 : int + +// ... + +L0 -> L1 { + bv1 := i1 + i1 := bv1 +} +``` + +## Algorithmic support for verification with bitvectors + +As of now, bitvectors are only partially supported due to the fact, that the underlying SMT solver, Z3 does not support interpolation when bitvectors are involved. + +As a result, CEGAR with predicate abstraction is not supported at all. However, CEGAR with explicit value abstraction, and with the UNSAT core refinement strategy is working preoperty, as it does not rely on the interpolation capabilities of the SMT solver. From 9411f776324399ef09f09f6d724e8500a94c8cf4 Mon Sep 17 00:00:00 2001 From: as3810t Date: Sun, 31 May 2020 20:17:06 +0200 Subject: [PATCH 16/23] Update README.md --- subprojects/cfa/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subprojects/cfa/README.md b/subprojects/cfa/README.md index 046f11c5fc..311103d48f 100644 --- a/subprojects/cfa/README.md +++ b/subprojects/cfa/README.md @@ -50,6 +50,8 @@ main process counter { See _src/test/resources_ for more examples and _src/main/antlr_ for the full grammar. +Bitvectors are now supported. Check out the [details](doc/bitvectors.md). + ### C frontend [Gazer](https://github.com/FTSRG/gazer) is an LLVM-based frontend for Theta that can translate C programs into CFAs, run Theta and map the verification results back to the C source level. From f67277465f4e22c0fc423dd38ff6bf6adeed2ffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Dobos-Kov=C3=A1cs?= Date: Sat, 18 Jul 2020 13:03:27 +0200 Subject: [PATCH 17/23] Add BvTests --- subprojects/cfa/src/test/resources/bv.cfa | 6 +- subprojects/cfa/src/test/resources/bv2.cfa | 4 +- .../mit/theta/core/type/bvtype/BvLitExpr.java | 24 +++-- .../hu/bme/mit/theta/core/utils/BvUtils.java | 24 +++++ .../type/bvtype/BvBasicOperationTest.java | 86 ++++++++++++++++++ .../type/bvtype/BvBitvectorOperationTest.java | 78 ++++++++++++++++ .../bvtype/BvRelationalOperationTest.java | 88 +++++++++++++++++++ .../bme/mit/theta/solver/z3/Z3SolverTest.java | 51 +++++++---- 8 files changed, 334 insertions(+), 27 deletions(-) create mode 100644 subprojects/core/src/test/java/hu/bme/mit/theta/core/type/bvtype/BvBasicOperationTest.java create mode 100644 subprojects/core/src/test/java/hu/bme/mit/theta/core/type/bvtype/BvBitvectorOperationTest.java create mode 100644 subprojects/core/src/test/java/hu/bme/mit/theta/core/type/bvtype/BvRelationalOperationTest.java diff --git a/subprojects/cfa/src/test/resources/bv.cfa b/subprojects/cfa/src/test/resources/bv.cfa index 2fc0a45420..2283c7feb1 100644 --- a/subprojects/cfa/src/test/resources/bv.cfa +++ b/subprojects/cfa/src/test/resources/bv.cfa @@ -11,7 +11,7 @@ main process cfa { L0 -> L1 { x := 4'd0 } L1 -> L2 { assume x < 4'd5 } L1 -> L3 { assume not (x < 4'd5) } - L2 -> L1 { x := (x + 4'd1) mod 4'd5 } - L3 -> END { assume x <= 4'd5 } - L3 -> ERR { assume not (x <= 4'd5) } + L2 -> L1 { x := (x + 4'd1) } + L3 -> END { assume x < 4'd5 } + L3 -> ERR { assume not (x < 4'd5) } } \ No newline at end of file diff --git a/subprojects/cfa/src/test/resources/bv2.cfa b/subprojects/cfa/src/test/resources/bv2.cfa index c66fab6685..8b6e8140da 100644 --- a/subprojects/cfa/src/test/resources/bv2.cfa +++ b/subprojects/cfa/src/test/resources/bv2.cfa @@ -8,10 +8,10 @@ main process cfa { final loc END error loc ERR - L0 -> L1 { x := 1 + 4'b0000 } + L0 -> L1 { x := 4'b0000 } L1 -> L2 { assume (x | 4'b0100) /= 4'b0100 } L1 -> L3 { assume not ((x | 4'b0100) /= 4'b0100) } L2 -> L1 { x := x * 4'd2 } - L3 -> END { assume (x & 4'b0100) /= 4'b0100 } + L3 -> END { assume (x & 4'b0100) = 4'b0100 } L3 -> ERR { assume not ((x & 4'b0100) /= 4'b0100) } } \ No newline at end of file diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java index c566f8b523..ce59e1a522 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java @@ -2,6 +2,7 @@ import static com.google.common.base.Preconditions.*; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; +import static hu.bme.mit.theta.core.type.bvtype.BvExprs.Bv; import static hu.bme.mit.theta.core.type.bvtype.BvExprs.BvType; import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; @@ -13,7 +14,9 @@ import hu.bme.mit.theta.core.utils.BvUtils; import java.math.BigInteger; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; public final class BvLitExpr extends NullaryExpr implements LitExpr, Comparable { @@ -112,20 +115,29 @@ public BvLitExpr not() { public BvLitExpr shiftLeft(final BvLitExpr that) { checkArgument(this.getType().equals(that.getType())); - BigInteger shift = BvUtils.bvLitExprToBigInteger(this); + + boolean[] shifted = Arrays.copyOf(this.getValue(), this.getValue().length); for(BigInteger i = BigInteger.ZERO; i.compareTo(BvUtils.bvLitExprToBigInteger(that)) < 0; i = i.add(BigInteger.ONE)) { - shift = shift.multiply(BigInteger.TWO); + for(int j = 0; j < shifted.length - 1; j++) { + shifted[j] = shifted[j + 1]; + } + shifted[shifted.length - 1] = false; } - return BvUtils.bigIntegerToBvLitExpr(shift, getType().getSize(), getType().isSigned()); + return Bv(shifted, getType().isSigned()); } public BvLitExpr shiftRight(final BvLitExpr that) { checkArgument(this.getType().equals(that.getType())); - BigInteger shift = BvUtils.bvLitExprToBigInteger(this); + + boolean[] shifted = Arrays.copyOf(this.getValue(), this.getValue().length); + boolean insert = shifted[0]; for(BigInteger i = BigInteger.ZERO; i.compareTo(BvUtils.bvLitExprToBigInteger(that)) < 0; i = i.add(BigInteger.ONE)) { - shift = shift.divide(BigInteger.TWO); + for(int j = shifted.length - 1; j > 0; j--) { + shifted[j] = shifted[j - 1]; + } + shifted[0] = insert; } - return BvUtils.bigIntegerToBvLitExpr(shift, getType().getSize(), getType().isSigned()); + return Bv(shifted, getType().isSigned()); } public BvLitExpr mod(final BvLitExpr that) { diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/BvUtils.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/BvUtils.java index 2079ee609a..6f1e002a05 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/BvUtils.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/BvUtils.java @@ -27,6 +27,10 @@ public static BigInteger bvLitExprToBigInteger(final BvLitExpr expr) { return integer; } + public static int bvLitExprToInt(final BvLitExpr expr) { + return bvLitExprToBigInteger(expr).intValue(); + } + public static BvLitExpr bigIntegerToBvLitExpr(BigInteger integer, final int size, final boolean isSigned) { if(isSigned && integer.compareTo(BigInteger.ZERO) < 0) { integer = integer.add(BigInteger.TWO.pow(size)); @@ -40,6 +44,26 @@ public static BvLitExpr bigIntegerToBvLitExpr(BigInteger integer, final int size return Bv(values, isSigned); } + public static BvLitExpr intToBvLitExpr(final int integer, final int size, final boolean isSigned) { + return bigIntegerToBvLitExpr(BigInteger.valueOf(integer), size, isSigned); + } + + public static BvLitExpr uint32ToBvLitExpr(final int integer) { + return intToBvLitExpr(integer, 32, false); + } + + public static BvLitExpr sint32ToBvLitExpr(final int integer) { + return intToBvLitExpr(integer, 32, true); + } + + public static BvLitExpr uint16ToBvLitExpr(final int integer) { + return intToBvLitExpr(integer, 16, false); + } + + public static BvLitExpr sint16ToBvLitExpr(final int integer) { + return intToBvLitExpr(integer, 16, true); + } + public static BigInteger fitBigIntegerIntoDomain(BigInteger integer, final int size, final boolean isSigned) { if(isSigned) { while(integer.compareTo(BigInteger.TWO.pow(size-1).negate()) < 0) { diff --git a/subprojects/core/src/test/java/hu/bme/mit/theta/core/type/bvtype/BvBasicOperationTest.java b/subprojects/core/src/test/java/hu/bme/mit/theta/core/type/bvtype/BvBasicOperationTest.java new file mode 100644 index 0000000000..5cfd359cf9 --- /dev/null +++ b/subprojects/core/src/test/java/hu/bme/mit/theta/core/type/bvtype/BvBasicOperationTest.java @@ -0,0 +1,86 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.ImmutableValuation; +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.Expr; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.*; + +import static hu.bme.mit.theta.core.utils.BvUtils.sint16ToBvLitExpr; +import static hu.bme.mit.theta.core.utils.BvUtils.uint16ToBvLitExpr; +import static hu.bme.mit.theta.core.type.bvtype.BvExprs.*; +import static org.junit.Assert.*; +import static org.junit.runners.Parameterized.*; + +@RunWith(Parameterized.class) +public class BvBasicOperationTest { + private final Class bvExpr; + private final Expr lhs; + private final Expr rhs; + + @Parameters + public static Collection operations() { + return Arrays.asList(new Object[][] { + /* Unsigned basic operations */ + { BvAddExpr.class, UBv16(4), Add(List.of(UBv16(1), UBv16(3))) }, + { BvSubExpr.class, UBv16(1), Sub(UBv16(4), UBv16(3)) }, + { BvMulExpr.class, UBv16(12), Mul(List.of(UBv16(4), UBv16(3))) }, + { BvDivExpr.class, UBv16(4), Div(UBv16(12), UBv16(3)) }, + { BvModExpr.class, UBv16(1), Mod(UBv16(13), UBv16(3)) }, + { BvRemExpr.class, UBv16(1), Rem(UBv16(13), UBv16(3)) }, + + /* Signed basic operations (positive) */ + { BvAddExpr.class, SBv16(4), Add(List.of(SBv16(1), SBv16(3))) }, + { BvSubExpr.class, SBv16(1), Sub(SBv16(4), SBv16(3)) }, + { BvMulExpr.class, SBv16(12), Mul(List.of(SBv16(4), SBv16(3))) }, + { BvDivExpr.class, SBv16(4), Div(SBv16(12), SBv16(3)) }, + { BvModExpr.class, SBv16(1), Mod(SBv16(13), SBv16(3)) }, + { BvRemExpr.class, SBv16(1), Rem(SBv16(13), SBv16(3)) }, + + /* Signed basic operations (negative) */ + { BvAddExpr.class, SBv16(4), Add(List.of(SBv16(-1), SBv16(5))) }, + { BvSubExpr.class, SBv16(-2), Sub(SBv16(4), SBv16(6)) }, + { BvMulExpr.class, SBv16(-12), Mul(List.of(SBv16(-4), SBv16(3))) }, + { BvDivExpr.class, SBv16(-4), Div(SBv16(12), SBv16(-3)) }, + { BvModExpr.class, SBv16(2), Mod(SBv16(-13), SBv16(3)) }, + { BvRemExpr.class, SBv16(-1), Rem(SBv16(13), SBv16(-3)) }, + { BvNegExpr.class, SBv16(-13), Neg(SBv16(13)) }, + + /* Signed basic operations (overflow) */ + { BvAddExpr.class, SBv16(-32768), Add(List.of(SBv16(32767), SBv16(1))) }, + { BvSubExpr.class, SBv16(32767), Sub(SBv16(-32768), SBv16(1)) }, + { BvMulExpr.class, SBv16(-32768), Mul(List.of(SBv16(16384), SBv16(2))) }, + }); + } + + public BvBasicOperationTest(Class bvExpr, Expr lhs, Expr rhs) { + this.bvExpr = bvExpr; + this.lhs = lhs; + this.rhs = rhs; + } + + @Test + public void testOperationEquals() { + Valuation val = ImmutableValuation.builder().build(); + assertNotNull(bvExpr); + assertEquals(lhs.eval(val), rhs.eval(val)); + } + + @Test + public void testOperationNotEquals() { + Valuation val = ImmutableValuation.builder().build(); + assertNotNull(bvExpr); + assertNotEquals((rhs.getType().isSigned() ? SBv16(0) : UBv16(0)).eval(val), rhs.eval(val)); + } + + private static BvLitExpr UBv16(int integer) { + return uint16ToBvLitExpr(integer); + } + + private static BvLitExpr SBv16(int integer) { + return sint16ToBvLitExpr(integer); + } +} diff --git a/subprojects/core/src/test/java/hu/bme/mit/theta/core/type/bvtype/BvBitvectorOperationTest.java b/subprojects/core/src/test/java/hu/bme/mit/theta/core/type/bvtype/BvBitvectorOperationTest.java new file mode 100644 index 0000000000..e87485b0a5 --- /dev/null +++ b/subprojects/core/src/test/java/hu/bme/mit/theta/core/type/bvtype/BvBitvectorOperationTest.java @@ -0,0 +1,78 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.ImmutableValuation; +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.Expr; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.*; + +import static hu.bme.mit.theta.core.utils.BvUtils.sint16ToBvLitExpr; +import static hu.bme.mit.theta.core.utils.BvUtils.uint16ToBvLitExpr; +import static hu.bme.mit.theta.core.type.bvtype.BvExprs.*; +import static org.junit.Assert.*; +import static org.junit.runners.Parameterized.*; + +@RunWith(Parameterized.class) +public class BvBitvectorOperationTest { + private final Class bvExpr; + private final Expr lhs; + private final Expr rhs; + + @Parameters + public static Collection operations() { + return Arrays.asList(new Object[][] { + /* Unsigned bitvector specific operations */ + { BvAndExpr.class, UBv16(1), And(List.of(UBv16(7), UBv16(9))) }, + { BvXorExpr.class, UBv16(14), Xor(List.of(UBv16(7), UBv16(9))) }, + { BvOrExpr.class, UBv16(15), Or(List.of(UBv16(7), UBv16(9))) }, + { BvShiftLeftExpr.class, UBv16(56), ShiftLeft(UBv16(7), UBv16(3)) }, + { BvShiftRightExpr.class, UBv16(3), ShiftRight(UBv16(7), UBv16(1)) }, + + /* Signed bitvector specific operations (positive) */ + { BvAndExpr.class, SBv16(1), And(List.of(SBv16(7), SBv16(9))) }, + { BvXorExpr.class, SBv16(14), Xor(List.of(SBv16(7), SBv16(9))) }, + { BvOrExpr.class, SBv16(15), Or(List.of(SBv16(7), SBv16(9))) }, + { BvShiftLeftExpr.class, SBv16(56), ShiftLeft(SBv16(7), SBv16(3)) }, + { BvShiftRightExpr.class, SBv16(3), ShiftRight(SBv16(7), SBv16(1)) }, + + /* Signed bitvector specific operations (negative) */ + { BvAndExpr.class, SBv16(9), And(List.of(SBv16(-7), SBv16(9))) }, + { BvXorExpr.class, SBv16(-16), Xor(List.of(SBv16(-7), SBv16(9))) }, + { BvOrExpr.class, SBv16(-7), Or(List.of(SBv16(-7), SBv16(9))) }, + { BvShiftLeftExpr.class, SBv16(-28), ShiftLeft(SBv16(-7), SBv16(2)) }, + { BvShiftRightExpr.class, SBv16(-2), ShiftRight(SBv16(-7), SBv16(2)) }, + { BvNotExpr.class, SBv16(-8), Not(SBv16(7)) }, + }); + } + + public BvBitvectorOperationTest(Class bvExpr, Expr lhs, Expr rhs) { + this.bvExpr = bvExpr; + this.lhs = lhs; + this.rhs = rhs; + } + + @Test + public void testOperationEquals() { + Valuation val = ImmutableValuation.builder().build(); + assertNotNull(bvExpr); + assertEquals(lhs.eval(val), rhs.eval(val)); + } + + @Test + public void testOperationNotEquals() { + Valuation val = ImmutableValuation.builder().build(); + assertNotNull(bvExpr); + assertNotEquals((rhs.getType().isSigned() ? SBv16(0) : UBv16(0)).eval(val), rhs.eval(val)); + } + + private static BvLitExpr UBv16(int integer) { + return uint16ToBvLitExpr(integer); + } + + private static BvLitExpr SBv16(int integer) { + return sint16ToBvLitExpr(integer); + } +} diff --git a/subprojects/core/src/test/java/hu/bme/mit/theta/core/type/bvtype/BvRelationalOperationTest.java b/subprojects/core/src/test/java/hu/bme/mit/theta/core/type/bvtype/BvRelationalOperationTest.java new file mode 100644 index 0000000000..8a60bf5e7a --- /dev/null +++ b/subprojects/core/src/test/java/hu/bme/mit/theta/core/type/bvtype/BvRelationalOperationTest.java @@ -0,0 +1,88 @@ +package hu.bme.mit.theta.core.type.bvtype; + +import hu.bme.mit.theta.core.model.ImmutableValuation; +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.booltype.BoolType; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.function.BiFunction; + +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.False; +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.True; +import static hu.bme.mit.theta.core.type.bvtype.BvExprs.*; +import static hu.bme.mit.theta.core.utils.BvUtils.sint16ToBvLitExpr; +import static hu.bme.mit.theta.core.utils.BvUtils.uint16ToBvLitExpr; +import static org.junit.Assert.*; +import static org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class BvRelationalOperationTest { + private final Expr lhs; + private final boolean result; + + @Parameters + public static Collection operations() { + return Arrays.asList(new Object[][] { + /* Unsigned relational operations */ + { Eq(UBv16(4), UBv16(4)), true }, + { Eq(UBv16(4), UBv16(5)), false }, + { Neq(UBv16(4), UBv16(4)), false }, + { Neq(UBv16(4), UBv16(5)), true }, + { Lt(UBv16(4), UBv16(5)), true }, + { Lt(UBv16(4), UBv16(4)), false }, + { Lt(UBv16(4), UBv16(3)), false }, + { Leq(UBv16(4), UBv16(5)), true }, + { Leq(UBv16(4), UBv16(4)), true }, + { Leq(UBv16(4), UBv16(3)), false }, + { Gt(UBv16(4), UBv16(5)), false }, + { Gt(UBv16(4), UBv16(4)), false }, + { Gt(UBv16(4), UBv16(3)), true }, + { Geq(UBv16(4), UBv16(5)), false }, + { Geq(UBv16(4), UBv16(4)), true }, + { Geq(UBv16(4), UBv16(3)), true }, + + /* Signed relational operations */ + { Eq(SBv16(4), SBv16(4)), true }, + { Eq(SBv16(4), SBv16(5)), false }, + { Neq(SBv16(4), SBv16(4)), false }, + { Neq(SBv16(4), SBv16(5)), true }, + { Lt(SBv16(4), SBv16(5)), true }, + { Lt(SBv16(4), SBv16(4)), false }, + { Lt(SBv16(4), SBv16(3)), false }, + { Leq(SBv16(4), SBv16(5)), true }, + { Leq(SBv16(4), SBv16(4)), true }, + { Leq(SBv16(4), SBv16(3)), false }, + { Gt(SBv16(4), SBv16(5)), false }, + { Gt(SBv16(4), SBv16(4)), false }, + { Gt(SBv16(4), SBv16(3)), true }, + { Geq(SBv16(4), SBv16(5)), false }, + { Geq(SBv16(4), SBv16(4)), true }, + { Geq(SBv16(4), SBv16(3)), true }, + }); + } + + public BvRelationalOperationTest(Expr lhs, Boolean result) { + this.lhs = lhs; + this.result = result; + } + + @Test + public void testOperationEquals() { + Valuation val = ImmutableValuation.builder().build(); + assertEquals(result ? True() : False(), lhs.eval(val)); + } + + private static BvLitExpr UBv16(int integer) { + return uint16ToBvLitExpr(integer); + } + + private static BvLitExpr SBv16(int integer) { + return sint16ToBvLitExpr(integer); + } +} diff --git a/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java b/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java index 8a2ce1fe04..928bfcd424 100644 --- a/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java +++ b/subprojects/solver-z3/src/test/java/hu/bme/mit/theta/solver/z3/Z3SolverTest.java @@ -22,6 +22,7 @@ import hu.bme.mit.theta.core.type.LitExpr; import hu.bme.mit.theta.core.type.booltype.BoolType; import hu.bme.mit.theta.core.type.bvtype.BvExprs; +import hu.bme.mit.theta.core.type.bvtype.BvLitExpr; import hu.bme.mit.theta.core.type.bvtype.BvType; import hu.bme.mit.theta.core.type.functype.FuncType; import hu.bme.mit.theta.core.type.inttype.IntType; @@ -40,6 +41,7 @@ import static hu.bme.mit.theta.core.type.functype.FuncExprs.App; import static hu.bme.mit.theta.core.type.functype.FuncExprs.Func; import static hu.bme.mit.theta.core.type.inttype.IntExprs.*; +import static hu.bme.mit.theta.core.utils.BvUtils.uint16ToBvLitExpr; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -164,7 +166,7 @@ public void testBV3() { solver.push(); solver.add(Eq(cx.getRef(), Bv(new boolean[] {false, false, false, false}, true))); - solver.add(Eq(cy.getRef(), BvExprs.Add(List.of(cx.getRef(), Bv(new boolean[] {false, false, false, true}, true))))); + solver.add(Eq(cy.getRef(), Add(List.of(cx.getRef(), Bv(new boolean[] {false, false, false, true}, true))))); SolverStatus status = solver.check(); assertTrue(status.isSat()); @@ -186,7 +188,7 @@ public void testBV4() { solver.push(); solver.add(Eq(cx.getRef(), Bv(new boolean[] {false, false, true, false}, true))); - solver.add(Eq(cy.getRef(), BvExprs.Sub(cx.getRef(), Bv(new boolean[] {false, false, false, true}, true)))); + solver.add(Eq(cy.getRef(), Sub(cx.getRef(), Bv(new boolean[] {false, false, false, true}, true)))); SolverStatus status = solver.check(); assertTrue(status.isSat()); @@ -208,7 +210,7 @@ public void testBV5() { solver.push(); solver.add(Eq(cx.getRef(), Bv(new boolean[] {false, false, true, false}, true))); - solver.add(Eq(cy.getRef(), BvExprs.Neg(cx.getRef()))); + solver.add(Eq(cy.getRef(), Neg(cx.getRef()))); SolverStatus status = solver.check(); assertTrue(status.isSat()); @@ -230,7 +232,7 @@ public void testBV6() { solver.push(); solver.add(Eq(cx.getRef(), Bv(new boolean[] {false, false, true, false}, true))); - solver.add(Eq(cy.getRef(), BvExprs.Mul(List.of(cx.getRef(), Bv(new boolean[] {false, false, true, false}, true))))); + solver.add(Eq(cy.getRef(), Mul(List.of(cx.getRef(), Bv(new boolean[] {false, false, true, false}, true))))); SolverStatus status = solver.check(); assertTrue(status.isSat()); @@ -251,8 +253,8 @@ public void testBV7() { solver.push(); - solver.add(BvExprs.Lt(cx.getRef(), Bv(new boolean[] {true, true, true, true}, true))); - solver.add(BvExprs.Lt(cy.getRef(), Bv(new boolean[] {true, true, true, true}, false))); + solver.add(Lt(cx.getRef(), Bv(new boolean[] {true, true, true, true}, true))); + solver.add(Lt(cy.getRef(), Bv(new boolean[] {true, true, true, true}, false))); SolverStatus status = solver.check(); assertTrue(status.isSat()); @@ -273,8 +275,8 @@ public void testBV8() { solver.push(); - solver.add(BvExprs.Eq(cx.getRef(), Bv(new boolean[] {true, false, true, false}, false))); - solver.add(BvExprs.Eq(cy.getRef(), BvExprs.Mod(cx.getRef(), Bv(new boolean[] {false, true, false, false}, false)))); + solver.add(Eq(cx.getRef(), Bv(new boolean[] {true, false, true, false}, false))); + solver.add(Eq(cy.getRef(), Mod(cx.getRef(), Bv(new boolean[] {false, true, false, false}, false)))); SolverStatus status = solver.check(); assertTrue(status.isSat()); @@ -295,8 +297,8 @@ public void testBV9() { solver.push(); - solver.add(BvExprs.Eq(cy.getRef(), Bv(new boolean[] {false, true, false, false}, false))); - solver.add(BvExprs.Eq(BvExprs.Or(List.of(cx.getRef(), cy.getRef())), Bv(new boolean[] {true, true, false, false}, false))); + solver.add(Eq(cy.getRef(), Bv(new boolean[] {false, true, false, false}, false))); + solver.add(Eq(Or(List.of(cx.getRef(), cy.getRef())), Bv(new boolean[] {true, true, false, false}, false))); SolverStatus status = solver.check(); assertTrue(status.isSat()); @@ -317,8 +319,8 @@ public void testBV10() { solver.push(); - solver.add(BvExprs.Eq(cy.getRef(), Bv(new boolean[] {false, true, false, false}, false))); - solver.add(BvExprs.Eq(BvExprs.And(List.of(cx.getRef(), cy.getRef())), Bv(new boolean[] {false, true, false, false}, false))); + solver.add(Eq(cy.getRef(), Bv(new boolean[] {false, true, false, false}, false))); + solver.add(Eq(And(List.of(cx.getRef(), cy.getRef())), Bv(new boolean[] {false, true, false, false}, false))); SolverStatus status = solver.check(); assertTrue(status.isSat()); @@ -339,8 +341,8 @@ public void testBV11() { solver.push(); - solver.add(BvExprs.Eq(cy.getRef(), Bv(new boolean[] {false, true, false, false}, false))); - solver.add(BvExprs.Eq(BvExprs.Xor(List.of(cx.getRef(), cy.getRef())), Bv(new boolean[] {false, true, false, false}, false))); + solver.add(Eq(cy.getRef(), Bv(new boolean[] {false, true, false, false}, false))); + solver.add(Eq(Xor(List.of(cx.getRef(), cy.getRef())), Bv(new boolean[] {false, true, false, false}, false))); SolverStatus status = solver.check(); assertTrue(status.isSat()); @@ -361,8 +363,8 @@ public void testBV12() { solver.push(); - solver.add(BvExprs.Eq(cy.getRef(), Bv(new boolean[] {false, true, false, false}, false))); - solver.add(BvExprs.Eq(BvExprs.ShiftRight(cy.getRef(), Bv(new boolean[] {false, false, false, true}, false)), cx.getRef())); + solver.add(Eq(cy.getRef(), Bv(new boolean[] {false, true, false, false}, false))); + solver.add(Eq(ShiftRight(cy.getRef(), Bv(new boolean[] {false, false, false, true}, false)), cx.getRef())); SolverStatus status = solver.check(); assertTrue(status.isSat()); @@ -374,4 +376,21 @@ public void testBV12() { solver.pop(); } + public void testBV13() { + final Solver solver = Z3SolverFactory.getInstace().createSolver(); + solver.push(); + + solver.add(Eq(uint16ToBvLitExpr(4), Add(List.of(uint16ToBvLitExpr(1), uint16ToBvLitExpr(3))))); + solver.add(Eq(uint16ToBvLitExpr(1), Sub(uint16ToBvLitExpr(4), uint16ToBvLitExpr(3)))); + solver.add(Eq(uint16ToBvLitExpr(12), Mul(List.of(uint16ToBvLitExpr(3), uint16ToBvLitExpr(4))))); + solver.add(Eq(uint16ToBvLitExpr(4), Div(uint16ToBvLitExpr(12), uint16ToBvLitExpr(3)))); + solver.add(Eq(uint16ToBvLitExpr(1), Mod(uint16ToBvLitExpr(13), uint16ToBvLitExpr(3)))); + solver.add(Eq(uint16ToBvLitExpr(1), Rem(uint16ToBvLitExpr(13), uint16ToBvLitExpr(3)))); + + } + + private static BvLitExpr UBv16(int integer) { + return uint16ToBvLitExpr(integer); + } + } From 1b5b0142205f13322ff9fa535e47cb9223d492df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Dobos-Kov=C3=A1cs?= Date: Sat, 18 Jul 2020 13:48:56 +0200 Subject: [PATCH 18/23] Add bitvector documentation to README --- subprojects/cfa/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/subprojects/cfa/README.md b/subprojects/cfa/README.md index 23e8f55d6b..302fd0692e 100644 --- a/subprojects/cfa/README.md +++ b/subprojects/cfa/README.md @@ -39,16 +39,19 @@ Variables of the CFA can have the following types. - `int`: Mathematical, unbounded SMT integers. - `rat`: Rational numbers (implemented as SMT reals). - `[K] -> V`: SMT arrays (associative maps) from a given key type `K` to a value type `V`. +- `bv[L]`, `bitvec[L]`, `ubv[L]`, `ubitvec[L]`, `sbv[L]`, `sbitvec[L]`: Signed or unsigned bitvector of given length. Expressions of the CFA include the following. - Identifiers (variables). - Literals, e.g., `true`, `false` (Bool), `0`, `123` (integer), `4 % 5` (rational). - Array literals can be given by listing the key-value pairs and the (mandatory) default element, e.g., `[0 <- 182, 1 <- 41, default <- 75]`. If there are no elements, the key type has to be given before the default element, e.g., `[default <- 75]`. + - Bitvector literals can be given by stating the length, information about the signedness, and the exact value of the bitvector in binary, decimal or hexadecimal form. (E.g. `4'd5` is a 4-bit-long unsigned bitvector with the decimal value 5.) For more information on bitvectors, check out the [details](doc/bitvectors.md). - Comparison, e.g., `=`, `/=`, `<`, `>`, `<=`, `>=`. - Boolean operators, e.g., `and`, `or`, `xor`, `not`, `imply`, `iff`. - Arithmetic, e.g., `+`, `-`, `/`, `*`, `mod`, `rem`. - Conditional: `if . then . else .` - Array read (`a[i]`) and write (`a[i <- v]`). +- Bitvector specific operators, e.g., `&`, `|`, `^`, `<<`, `>>`, `~`. For more information on bitvectors, check out the [details](doc/bitvectors.md). ### Textual representation (DSL) @@ -79,8 +82,6 @@ Note that it is also possible to include multiple statements on one edge (in new See _src/test/resources_ for more examples and _src/main/antlr_ for the full grammar. -Bitvectors are now supported. Check out the [details](doc/bitvectors.md). - ### C frontend [Gazer](https://github.com/FTSRG/gazer) is an LLVM-based frontend for Theta that can translate C programs into CFAs, run Theta and map the verification results back to the C source level. From adb1cc2761624bef969c563663492d6e1683cec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Dobos-Kov=C3=A1cs?= Date: Mon, 20 Jul 2020 20:38:07 +0200 Subject: [PATCH 19/23] Code cleanup --- .../hu/bme/mit/theta/cfa/dsl/CfaExpression.java | 1 - .../java/hu/bme/mit/theta/cfa/dsl/CfaType.java | 6 ------ .../bme/mit/theta/core/dsl/impl/ExprWriter.java | 2 +- .../mit/theta/core/type/booltype/BoolLitExpr.java | 2 +- .../bme/mit/theta/core/type/bvtype/BvLitExpr.java | 15 +++++++-------- .../hu/bme/mit/theta/core/type/bvtype/BvType.java | 1 + .../mit/theta/core/type/inttype/IntModExpr.java | 1 - .../mit/theta/core/type/inttype/IntRemExpr.java | 1 - .../mit/theta/core/type/inttype/package-info.java | 4 ++-- .../hu/bme/mit/theta/core/utils/TypeUtils.java | 1 - .../mit/theta/solver/z3/Z3TermTransformer.java | 7 +------ .../mit/theta/solver/z3/Z3TypeTransformer.java | 1 - 12 files changed, 13 insertions(+), 29 deletions(-) diff --git a/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java b/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java index 6634758279..dd80016fc0 100644 --- a/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java +++ b/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaExpression.java @@ -17,7 +17,6 @@ import com.google.common.collect.ImmutableList; import hu.bme.mit.theta.cfa.dsl.gen.CfaDslBaseVisitor; -import hu.bme.mit.theta.cfa.dsl.gen.CfaDslParser.*; import hu.bme.mit.theta.common.Tuple2; import hu.bme.mit.theta.common.dsl.BasicScope; import hu.bme.mit.theta.common.dsl.Env; diff --git a/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaType.java b/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaType.java index 2c58ab7625..56e1f56092 100644 --- a/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaType.java +++ b/subprojects/cfa/src/main/java/hu/bme/mit/theta/cfa/dsl/CfaType.java @@ -24,12 +24,6 @@ import static hu.bme.mit.theta.core.type.rattype.RatExprs.Rat; import hu.bme.mit.theta.cfa.dsl.gen.CfaDslBaseVisitor; -import hu.bme.mit.theta.cfa.dsl.gen.CfaDslParser; -import hu.bme.mit.theta.cfa.dsl.gen.CfaDslParser.ArrayTypeContext; -import hu.bme.mit.theta.cfa.dsl.gen.CfaDslParser.BoolTypeContext; -import hu.bme.mit.theta.cfa.dsl.gen.CfaDslParser.IntTypeContext; -import hu.bme.mit.theta.cfa.dsl.gen.CfaDslParser.RatTypeContext; -import hu.bme.mit.theta.cfa.dsl.gen.CfaDslParser.TypeContext; import hu.bme.mit.theta.core.type.Type; final class CfaType { diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/dsl/impl/ExprWriter.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/dsl/impl/ExprWriter.java index 9875fd3b9a..1251cb9a71 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/dsl/impl/ExprWriter.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/dsl/impl/ExprWriter.java @@ -68,7 +68,7 @@ public final class ExprWriter { private final DispatchTable table; private static class LazyHolder { - private static ExprWriter INSTANCE = new ExprWriter(); + private static final ExprWriter INSTANCE = new ExprWriter(); } public static ExprWriter instance() { diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/booltype/BoolLitExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/booltype/BoolLitExpr.java index e98e9f841f..cea0983d10 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/booltype/BoolLitExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/booltype/BoolLitExpr.java @@ -22,7 +22,7 @@ public abstract class BoolLitExpr extends NullaryExpr implements LitEx public abstract boolean getValue(); - public static final BoolLitExpr of(final boolean value) { + public static BoolLitExpr of(final boolean value) { return value ? TrueExpr.getInstance() : FalseExpr.getInstance(); } diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java index ce59e1a522..522cafcc7a 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvLitExpr.java @@ -1,11 +1,5 @@ package hu.bme.mit.theta.core.type.bvtype; -import static com.google.common.base.Preconditions.*; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; -import static hu.bme.mit.theta.core.type.bvtype.BvExprs.Bv; -import static hu.bme.mit.theta.core.type.bvtype.BvExprs.BvType; -import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; - import hu.bme.mit.theta.core.model.Valuation; import hu.bme.mit.theta.core.type.LitExpr; import hu.bme.mit.theta.core.type.NullaryExpr; @@ -14,9 +8,14 @@ import hu.bme.mit.theta.core.utils.BvUtils; import java.math.BigInteger; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; +import static hu.bme.mit.theta.core.type.bvtype.BvExprs.Bv; +import static hu.bme.mit.theta.core.type.bvtype.BvExprs.BvType; +import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; public final class BvLitExpr extends NullaryExpr implements LitExpr, Comparable { diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java index 806fa9928c..df1aaa5d24 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java @@ -101,6 +101,7 @@ public GeqExpr Geq(Expr leftOp, Expr rightOp) { return BvGeqExpr.of(leftOp, rightOp); } + @SuppressWarnings("unchecked") @Override public Expr Cast(final Expr op, final TargetType type) { if (type instanceof IntType) { diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntModExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntModExpr.java index 094238595e..30e88671b1 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntModExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntModExpr.java @@ -19,7 +19,6 @@ import static hu.bme.mit.theta.core.utils.TypeUtils.cast; import hu.bme.mit.theta.core.model.Valuation; -import hu.bme.mit.theta.core.type.BinaryExpr; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.abstracttype.ModExpr; diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntRemExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntRemExpr.java index c8753d0981..3625df9c0f 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntRemExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntRemExpr.java @@ -19,7 +19,6 @@ import static hu.bme.mit.theta.core.utils.TypeUtils.cast; import hu.bme.mit.theta.core.model.Valuation; -import hu.bme.mit.theta.core.type.BinaryExpr; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.abstracttype.RemExpr; diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/package-info.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/package-info.java index 6d13a4bc81..b1613461a9 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/package-info.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/package-info.java @@ -12,8 +12,8 @@ * - {@link hu.bme.mit.theta.core.type.inttype.IntSubExpr}: subtraction * - {@link hu.bme.mit.theta.core.type.inttype.IntMulExpr}: multiplication * - {@link hu.bme.mit.theta.core.type.inttype.IntDivExpr}: integer division - * - {@link hu.bme.mit.theta.core.type.inttype.ModExpr}: modulus - * - {@link hu.bme.mit.theta.core.type.inttype.RemExpr}: remainder + * - {@link hu.bme.mit.theta.core.type.inttype.IntModExpr}: modulus + * - {@link hu.bme.mit.theta.core.type.inttype.IntRemExpr}: remainder * * - {@link hu.bme.mit.theta.core.type.inttype.IntEqExpr}: equal * - {@link hu.bme.mit.theta.core.type.inttype.IntNegExpr}: not equal diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/TypeUtils.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/TypeUtils.java index e44a61c94e..4be1eb98ac 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/TypeUtils.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/utils/TypeUtils.java @@ -25,7 +25,6 @@ import hu.bme.mit.theta.core.type.bvtype.BvType; import java.util.Iterator; -import java.util.List; /** * Utility functions related to types. diff --git a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TermTransformer.java b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TermTransformer.java index 4c42207a53..57e5e42ccf 100644 --- a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TermTransformer.java +++ b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TermTransformer.java @@ -23,7 +23,6 @@ import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Exists; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Forall; -import static hu.bme.mit.theta.core.type.bvtype.BvExprs.Bv; import static hu.bme.mit.theta.core.type.functype.FuncExprs.App; import static hu.bme.mit.theta.core.type.functype.FuncExprs.Func; import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; @@ -31,10 +30,6 @@ import static java.lang.String.format; import java.math.BigInteger; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import java.util.*; import java.util.function.BinaryOperator; import java.util.function.Function; @@ -210,7 +205,7 @@ private Expr transformBvLit(final com.microsoft.z3.Expr term) { return BvUtils.bigIntegerToBvLitExpr(value, bvNum.getSortSize(), false); } - private final Expr transformApp(final com.microsoft.z3.Expr term, final com.microsoft.z3.Model model, + private Expr transformApp(final com.microsoft.z3.Expr term, final com.microsoft.z3.Model model, final List> vars) { final com.microsoft.z3.FuncDecl funcDecl = term.getFuncDecl(); diff --git a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TypeTransformer.java b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TypeTransformer.java index 97b7833314..783723e882 100644 --- a/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TypeTransformer.java +++ b/subprojects/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TypeTransformer.java @@ -25,7 +25,6 @@ import hu.bme.mit.theta.core.type.inttype.IntType; import hu.bme.mit.theta.core.type.rattype.RatType; -import java.util.HashSet; import java.util.Optional; import java.util.Set; import java.util.TreeSet; From 3a938983ded6fb5f568e929ce5a68a722d6a7815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hajdu=20=C3=81kos?= Date: Tue, 28 Jul 2020 23:40:14 +0200 Subject: [PATCH 20/23] Fix typos --- subprojects/cfa/src/main/antlr/CfaDsl.g4 | 4 ++-- .../java/hu/bme/mit/theta/core/type/inttype/IntLitExpr.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/subprojects/cfa/src/main/antlr/CfaDsl.g4 b/subprojects/cfa/src/main/antlr/CfaDsl.g4 index aaaf8727b6..341e61d99f 100644 --- a/subprojects/cfa/src/main/antlr/CfaDsl.g4 +++ b/subprojects/cfa/src/main/antlr/CfaDsl.g4 @@ -80,7 +80,7 @@ type: boolType | ratType | funcType | arrayType - | bvType + | bvType ; typeList @@ -277,7 +277,7 @@ primaryExpr | intLitExpr | ratLitExpr | arrLitExpr - | bvLitExpr + | bvLitExpr | idExpr | parenExpr ; diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntLitExpr.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntLitExpr.java index baaca20348..1a219e1f0c 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntLitExpr.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntLitExpr.java @@ -69,7 +69,7 @@ public BvLitExpr toBv(int size, boolean isSigned) { if(res.equals(fittedRes)) { return BvUtils.bigIntegerToBvLitExpr(fittedRes, size, isSigned); } else { - throw new IllegalArgumentException("The value of int " + res.toString() + " does not fit the bitfector " + (isSigned ? "signed" : "unsigned") + " domain of size " + size + " bits"); + throw new IllegalArgumentException("The value of int " + res.toString() + " does not fit the bitvector " + (isSigned ? "signed" : "unsigned") + " domain of size " + size + " bits"); } } From 9339f12efbb510f955204909429f9ccdc5dd85b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hajdu=20=C3=81kos?= Date: Tue, 28 Jul 2020 23:54:16 +0200 Subject: [PATCH 21/23] Extend readme --- subprojects/cfa/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subprojects/cfa/README.md b/subprojects/cfa/README.md index 302fd0692e..790f4504f1 100644 --- a/subprojects/cfa/README.md +++ b/subprojects/cfa/README.md @@ -39,19 +39,19 @@ Variables of the CFA can have the following types. - `int`: Mathematical, unbounded SMT integers. - `rat`: Rational numbers (implemented as SMT reals). - `[K] -> V`: SMT arrays (associative maps) from a given key type `K` to a value type `V`. -- `bv[L]`, `bitvec[L]`, `ubv[L]`, `ubitvec[L]`, `sbv[L]`, `sbitvec[L]`: Signed or unsigned bitvector of given length. +- `bv[L]`, `bitvec[L]`, `ubv[L]`, `ubitvec[L]`, `sbv[L]`, `sbitvec[L]`: Signed or unsigned bitvector of given length `L`. _This is an experimental feature with currently limited algorithmic support. See the [details](doc/bitvectors.md) for more information._ Expressions of the CFA include the following. - Identifiers (variables). - Literals, e.g., `true`, `false` (Bool), `0`, `123` (integer), `4 % 5` (rational). - Array literals can be given by listing the key-value pairs and the (mandatory) default element, e.g., `[0 <- 182, 1 <- 41, default <- 75]`. If there are no elements, the key type has to be given before the default element, e.g., `[default <- 75]`. - - Bitvector literals can be given by stating the length, information about the signedness, and the exact value of the bitvector in binary, decimal or hexadecimal form. (E.g. `4'd5` is a 4-bit-long unsigned bitvector with the decimal value 5.) For more information on bitvectors, check out the [details](doc/bitvectors.md). + - Bitvector literals can be given by stating the length, information about the signedness, and the exact value of the bitvector in binary, decimal or hexadecimal form. (E.g. `4'd5` is a 4-bit-long unsigned bitvector with the decimal value 5.) _This is an experimental feature with currently limited algorithmic support. See the [details](doc/bitvectors.md) for more information._ - Comparison, e.g., `=`, `/=`, `<`, `>`, `<=`, `>=`. - Boolean operators, e.g., `and`, `or`, `xor`, `not`, `imply`, `iff`. - Arithmetic, e.g., `+`, `-`, `/`, `*`, `mod`, `rem`. - Conditional: `if . then . else .` - Array read (`a[i]`) and write (`a[i <- v]`). -- Bitvector specific operators, e.g., `&`, `|`, `^`, `<<`, `>>`, `~`. For more information on bitvectors, check out the [details](doc/bitvectors.md). +- Bitvector specific operators, e.g., `&`, `|`, `^`, `<<`, `>>`, `~`. _This is an experimental feature with currently limited algorithmic support. See the [details](doc/bitvectors.md) for more information._ ### Textual representation (DSL) From 324473c05b39242e2274e618fa5c8e16c7c39742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hajdu=20=C3=81kos?= Date: Wed, 29 Jul 2020 00:06:44 +0200 Subject: [PATCH 22/23] Add some more docs --- subprojects/core/README.md | 2 +- .../theta/core/type/bvtype/package-info.java | 35 +++++++++++++++++++ .../bme/mit/theta/core/type/package-info.java | 1 + 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/package-info.java diff --git a/subprojects/core/README.md b/subprojects/core/README.md index 1555d98714..9f7ba668ca 100644 --- a/subprojects/core/README.md +++ b/subprojects/core/README.md @@ -1,7 +1,7 @@ This project provides classes and utilities to build and manipulate first order logic (FOL) expressions, statements and related concepts, which serve as a basis for the formalisms and analyses. Classes include -* types (e.g., Boolean, integer, rational, array), +* types (e.g., Boolean, integer, rational, array, bitvector), see the [`package-info.java`](src/main/java/hu/bme/mit/theta/core/type/package-info.java) for more details, * declarations (e.g., constants, variables), see the [`package-info.java`](src/main/java/hu/bme/mit/theta/core/decl/package-info.java) for more details, diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/package-info.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/package-info.java new file mode 100644 index 0000000000..c63f42918f --- /dev/null +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/package-info.java @@ -0,0 +1,35 @@ +/** + * Bitvector type and its expressions. Use {@link hu.bme.mit.theta.core.type.bvtype.BvExprs} to create them. + * Bitvectors can be used to simulate machine integers that can be signed/unsigned with a fixed range and + * wraparound overflow semantics. For example, 255+1 on 8 unsigned bits will result in 0. + * + * - {@link hu.bme.mit.theta.core.type.bvtype.BvType}: the actual bitvector type + * + * - {@link hu.bme.mit.theta.core.type.bvtype.BvLitExpr}: bitvector literal + * + * - {@link hu.bme.mit.theta.core.type.bvtype.BvNegExpr}: unary minus + * - {@link hu.bme.mit.theta.core.type.bvtype.BvAddExpr}: addition + * - {@link hu.bme.mit.theta.core.type.bvtype.BvSubExpr}: subtraction + * - {@link hu.bme.mit.theta.core.type.bvtype.BvMulExpr}: multiplication + * - {@link hu.bme.mit.theta.core.type.bvtype.BvDivExpr}: division + * - {@link hu.bme.mit.theta.core.type.bvtype.BvModExpr}: modulus + * - {@link hu.bme.mit.theta.core.type.bvtype.BvRemExpr}: remainder + * + * - {@link hu.bme.mit.theta.core.type.bvtype.BvNotExpr}: bitwise not + * - {@link hu.bme.mit.theta.core.type.bvtype.BvAndExpr}: bitwise and + * - {@link hu.bme.mit.theta.core.type.bvtype.BvOrExpr}: bitwise or + * - {@link hu.bme.mit.theta.core.type.bvtype.BvXorExpr}: bitwise xor + * - {@link hu.bme.mit.theta.core.type.bvtype.BvShiftLeftExpr}: shift left + * - {@link hu.bme.mit.theta.core.type.bvtype.BvShiftRightExpr}: shift right + * + * - {@link hu.bme.mit.theta.core.type.bvtype.BvEqExpr}: equal + * - {@link hu.bme.mit.theta.core.type.bvtype.BvNeqExpr}: not equal + * - {@link hu.bme.mit.theta.core.type.bvtype.BvGtExpr}: greater + * - {@link hu.bme.mit.theta.core.type.bvtype.BvLtExpr}: less + * - {@link hu.bme.mit.theta.core.type.bvtype.BvGeqExpr}: greater or equal + * - {@link hu.bme.mit.theta.core.type.bvtype.BvLeqExpr}: less or equal + * + * - {@link hu.bme.mit.theta.core.type.bvtype.BvToIntExpr}: cast to int + */ + +package hu.bme.mit.theta.core.type.bvtype; \ No newline at end of file diff --git a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/package-info.java b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/package-info.java index 4dc48c9e3c..5c4451e0b1 100644 --- a/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/package-info.java +++ b/subprojects/core/src/main/java/hu/bme/mit/theta/core/type/package-info.java @@ -9,6 +9,7 @@ * - {@link hu.bme.mit.theta.core.type.anytype} and {@link hu.bme.mit.theta.core.type.abstracttype} * are expressions for multiple types (e.g., conditional). * - {@link hu.bme.mit.theta.core.type.booltype} contains the Boolean type and expressions (e.g., and, or). + * - {@link hu.bme.mit.theta.core.type.bvtype} contains the (SMT) bitvector type and expressions (e.g., bitwise and, shifts). * - {@link hu.bme.mit.theta.core.type.inttype} contains the mathematical (SMT) integer type and expressions * (e.g., add, multiply). * - {@link hu.bme.mit.theta.core.type.rattype} contains the rational type and expression (e.g., division). From ff73098ba7956c560019732333952c246fab2e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hajdu=20=C3=81kos?= Date: Wed, 29 Jul 2020 10:28:43 +0200 Subject: [PATCH 23/23] Bump version --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index f09e18beac..fdb975a036 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,7 +10,7 @@ buildscript { allprojects { group = "hu.bme.mit.inf.theta" - version = "1.3.0" + version = "1.4.0" apply(from = rootDir.resolve("gradle/shared-with-buildSrc/mirrors.gradle.kts")) }