diff --git a/src/main/java/leon/codegen/runtime/BigInt.java b/src/main/java/leon/codegen/runtime/BigInt.java index 83de0fbb4f16ec82843cc64a0bb7eb08f6081148..f2b99a6d9b07234ef247bb6c18bdbd0a37e73733 100644 --- a/src/main/java/leon/codegen/runtime/BigInt.java +++ b/src/main/java/leon/codegen/runtime/BigInt.java @@ -40,7 +40,10 @@ public final class BigInt { } public BigInt mod(BigInt that) { - return new BigInt(_underlying.mod(that.underlying())); + if(that.underlying().compareTo(new BigInteger("0")) < 0) + return new BigInt(_underlying.mod(that.underlying().negate())); + else + return new BigInt(_underlying.mod(that.underlying())); } public BigInt neg() { diff --git a/src/main/scala/leon/codegen/CodeGeneration.scala b/src/main/scala/leon/codegen/CodeGeneration.scala index 4125eadddc4b3446d15cf5be6e9dc408c510fa4c..5d2b7fd419cdd2b92e0bce2e583de881307442fb 100644 --- a/src/main/scala/leon/codegen/CodeGeneration.scala +++ b/src/main/scala/leon/codegen/CodeGeneration.scala @@ -645,12 +645,16 @@ trait CodeGeneration { mkExpr(r, ch) ch << InvokeVirtual(BigIntClass, "div", s"(L$BigIntClass;)L$BigIntClass;") - //Modulo in Leon corresponds to the "rem" operator on java/Scala BigInt - case Modulo(l, r) => + case Remainder(l, r) => mkExpr(l, ch) mkExpr(r, ch) ch << InvokeVirtual(BigIntClass, "rem", s"(L$BigIntClass;)L$BigIntClass;") + case Modulo(l, r) => + mkExpr(l, ch) + mkExpr(r, ch) + ch << InvokeVirtual(BigIntClass, "mod", s"(L$BigIntClass;)L$BigIntClass;") + case UMinus(e) => mkExpr(e, ch) ch << InvokeVirtual(BigIntClass, "neg", s"()L$BigIntClass;") @@ -676,7 +680,7 @@ trait CodeGeneration { mkExpr(r, ch) ch << IDIV - case BVModulo(l, r) => + case BVRemainder(l, r) => mkExpr(l, ch) mkExpr(r, ch) ch << IREM diff --git a/src/main/scala/leon/evaluators/RecursiveEvaluator.scala b/src/main/scala/leon/evaluators/RecursiveEvaluator.scala index 86e6ef578a24b37c63e45398e31fd4c30afaa15b..90ea4ace4de5ff0c210596ea7a99e96a02890443 100644 --- a/src/main/scala/leon/evaluators/RecursiveEvaluator.scala +++ b/src/main/scala/leon/evaluators/RecursiveEvaluator.scala @@ -289,10 +289,21 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, maxSteps: Int case (le,re) => throw EvalError(typeErrorMsg(le, IntegerType)) } + case Remainder(l,r) => + (e(l), e(r)) match { + case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => + if(i2 != BigInt(0)) InfiniteIntegerLiteral(i1 % i2) else throw RuntimeError("Remainder of division by 0.") + case (le,re) => throw EvalError(typeErrorMsg(le, IntegerType)) + } case Modulo(l,r) => (e(l), e(r)) match { case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => - if(i2 != BigInt(0)) InfiniteIntegerLiteral(i1 % i2) else throw RuntimeError("Modulo by 0.") + if(i2 < 0) + InfiniteIntegerLiteral(i1 mod (-i2)) + else if(i2 != BigInt(0)) + InfiniteIntegerLiteral(i1 mod i2) + else + throw RuntimeError("Modulo of division by 0.") case (le,re) => throw EvalError(typeErrorMsg(le, IntegerType)) } @@ -309,10 +320,10 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, maxSteps: Int case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type)) } - case BVModulo(l,r) => + case BVRemainder(l,r) => (e(l), e(r)) match { case (IntLiteral(i1), IntLiteral(i2)) => - if(i2 != 0) IntLiteral(i1 % i2) else throw RuntimeError("Modulo by 0.") + if(i2 != 0) IntLiteral(i1 % i2) else throw RuntimeError("Remainder of division by 0.") case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type)) } diff --git a/src/main/scala/leon/frontends/scalac/CodeExtraction.scala b/src/main/scala/leon/frontends/scalac/CodeExtraction.scala index 2047200929bf3e3d9876e4e01f0ab5eefab34708..4466dbc231ede94258654164e21cfd0ca0dccf83 100644 --- a/src/main/scala/leon/frontends/scalac/CodeExtraction.scala +++ b/src/main/scala/leon/frontends/scalac/CodeExtraction.scala @@ -1596,6 +1596,8 @@ trait CodeExtraction extends ASTExtractors { case (IsTyped(a1, IntegerType), "*", List(IsTyped(a2, IntegerType))) => Times(a1, a2) case (IsTyped(a1, IntegerType), "%", List(IsTyped(a2, IntegerType))) => + Remainder(a1, a2) + case (IsTyped(a1, IntegerType), "mod", List(IsTyped(a2, IntegerType))) => Modulo(a1, a2) case (IsTyped(a1, IntegerType), "/", List(IsTyped(a2, IntegerType))) => Division(a1, a2) @@ -1616,7 +1618,7 @@ trait CodeExtraction extends ASTExtractors { case (IsTyped(a1, Int32Type), "*", List(IsTyped(a2, Int32Type))) => BVTimes(a1, a2) case (IsTyped(a1, Int32Type), "%", List(IsTyped(a2, Int32Type))) => - BVModulo(a1, a2) + BVRemainder(a1, a2) case (IsTyped(a1, Int32Type), "/", List(IsTyped(a2, Int32Type))) => BVDivision(a1, a2) diff --git a/src/main/scala/leon/purescala/Expressions.scala b/src/main/scala/leon/purescala/Expressions.scala index 2a75af65cfecee84e2c4f24b061af22f81256f42..e852d55c0e71f58bcedf0ee0742897b572969a68 100644 --- a/src/main/scala/leon/purescala/Expressions.scala +++ b/src/main/scala/leon/purescala/Expressions.scala @@ -326,19 +326,23 @@ object Expressions { val getType = IntegerType } /* - * Division and Modulo follows Java/Scala semantics. Division corresponds - * to / operator on BigInt and Modulo corresponds to %. Note that in - * Java/Scala % is rather called remainder and the "mod" operator is also - * defined on BigInteger and differs from our Modulo. The "mod" operator - * returns an always positive remainder, while our Modulo could return + * Division and Remainder follows Java/Scala semantics. Division corresponds + * to / operator on BigInt and Remainder corresponds to %. Note that in + * Java/Scala % is called remainder and the "mod" operator (Modulo in Leon) is also + * defined on BigInteger and differs from Remainder. The "mod" operator + * returns an always positive remainder, while Remainder could return * a negative remainder. The following must hold: * - * Division(x, y) * y + Modulo(x, y) == x + * Division(x, y) * y + Remainder(x, y) == x */ case class Division(lhs: Expr, rhs: Expr) extends Expr { require(lhs.getType == IntegerType && rhs.getType == IntegerType) val getType = IntegerType } + case class Remainder(lhs: Expr, rhs: Expr) extends Expr { + require(lhs.getType == IntegerType && rhs.getType == IntegerType) + val getType = IntegerType + } case class Modulo(lhs: Expr, rhs: Expr) extends Expr { require(lhs.getType == IntegerType && rhs.getType == IntegerType) val getType = IntegerType @@ -377,7 +381,7 @@ object Expressions { require(lhs.getType == Int32Type && rhs.getType == Int32Type) val getType = Int32Type } - case class BVModulo(lhs: Expr, rhs: Expr) extends Expr { + case class BVRemainder(lhs: Expr, rhs: Expr) extends Expr { require(lhs.getType == Int32Type && rhs.getType == Int32Type) val getType = Int32Type } diff --git a/src/main/scala/leon/purescala/Extractors.scala b/src/main/scala/leon/purescala/Extractors.scala index 249c4622e1c54807404ff64051b7d570bd48b415..0bacc4a72c160f7c04297c4e7a4d3153b36512d2 100644 --- a/src/main/scala/leon/purescala/Extractors.scala +++ b/src/main/scala/leon/purescala/Extractors.scala @@ -52,6 +52,7 @@ object Extractors { case Minus(t1,t2) => Some((t1,t2,Minus)) case Times(t1,t2) => Some((t1,t2,Times)) case Division(t1,t2) => Some((t1,t2,Division)) + case Remainder(t1,t2) => Some((t1,t2,Remainder)) case Modulo(t1,t2) => Some((t1,t2,Modulo)) case LessThan(t1,t2) => Some((t1,t2,LessThan)) case GreaterThan(t1,t2) => Some((t1,t2,GreaterThan)) @@ -61,7 +62,7 @@ object Extractors { case BVMinus(t1,t2) => Some((t1,t2,BVMinus)) case BVTimes(t1,t2) => Some((t1,t2,BVTimes)) case BVDivision(t1,t2) => Some((t1,t2,BVDivision)) - case BVModulo(t1,t2) => Some((t1,t2,BVModulo)) + case BVRemainder(t1,t2) => Some((t1,t2,BVRemainder)) case BVAnd(t1,t2) => Some((t1,t2,BVAnd)) case BVOr(t1,t2) => Some((t1,t2,BVOr)) case BVXOr(t1,t2) => Some((t1,t2,BVXOr)) diff --git a/src/main/scala/leon/purescala/PrettyPrinter.scala b/src/main/scala/leon/purescala/PrettyPrinter.scala index b274f8edaaf045ce8f6a1dd8638c2e419317fa01..9dbcf09895c76030c01cff8c6048aa49ddc16c0a 100644 --- a/src/main/scala/leon/purescala/PrettyPrinter.scala +++ b/src/main/scala/leon/purescala/PrettyPrinter.scala @@ -357,7 +357,8 @@ class PrettyPrinter(opts: PrinterOptions, val sb: StringBuffer = new StringBuffe case Minus(l,r) => optP { p"$l - $r" } case Times(l,r) => optP { p"$l * $r" } case Division(l,r) => optP { p"$l / $r" } - case Modulo(l,r) => optP { p"$l % $r" } + case Remainder(l,r) => optP { p"$l % $r" } + case Modulo(l,r) => optP { p"$l mod $r" } case LessThan(l,r) => optP { p"$l < $r" } case GreaterThan(l,r) => optP { p"$l > $r" } case LessEquals(l,r) => optP { p"$l <= $r" } @@ -366,7 +367,7 @@ class PrettyPrinter(opts: PrinterOptions, val sb: StringBuffer = new StringBuffe case BVMinus(l,r) => optP { p"$l - $r" } case BVTimes(l,r) => optP { p"$l * $r" } case BVDivision(l,r) => optP { p"$l / $r" } - case BVModulo(l,r) => optP { p"$l % $r" } + case BVRemainder(l,r) => optP { p"$l % $r" } case BVAnd(l,r) => optP { p"$l & $r" } case BVOr(l,r) => optP { p"$l | $r" } case BVXOr(l,r) => optP { p"$l ^ $r" } @@ -741,9 +742,10 @@ class PrettyPrinter(opts: PrinterOptions, val sb: StringBuffer = new StringBuffe case (_: And | BinaryMethodCall(_, "&&", _)) => 3 case (_: GreaterThan | _: GreaterEquals | _: LessEquals | _: LessThan) => 4 case (_: Equals | _: Not) => 5 - case (_: Plus | _: BVPlus | _: Minus | _: BVMinus | _: SetUnion| _: SetDifference | BinaryMethodCall(_, "+" | "-", _)) => 6 - case (_: Times | _: BVTimes | _: Division | _: BVDivision | _: Modulo | _: BVModulo | BinaryMethodCall(_, "*" | "/", _)) => 7 - case _ => 7 + case (_: Modulo) => 6 + case (_: Plus | _: BVPlus | _: Minus | _: BVMinus | _: SetUnion| _: SetDifference | BinaryMethodCall(_, "+" | "-", _)) => 7 + case (_: Times | _: BVTimes | _: Division | _: BVDivision | _: Remainder | _: BVRemainder | BinaryMethodCall(_, "*" | "/", _)) => 8 + case _ => 9 } def requiresParentheses(ex: Tree, within: Option[Tree]): Boolean = (ex, within) match { diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBSolver.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBSolver.scala index ae77673d813e66d10a0e0a75451f0a0ef3ba82d1..0ac1f11e6b173fc6be0ab5b0cb297a3e2af4c7d4 100644 --- a/src/main/scala/leon/solvers/smtlib/SMTLIBSolver.scala +++ b/src/main/scala/leon/solvers/smtlib/SMTLIBSolver.scala @@ -649,10 +649,13 @@ abstract class SMTLIBSolver(val context: LeonContext, Ints.Div(ar, br), Ints.Neg(Ints.Div(Ints.Neg(ar), br))) } - case Modulo(a,b) => { + case Remainder(a,b) => { val q = toSMT(Division(a, b)) Ints.Sub(toSMT(a), Ints.Mul(toSMT(b), q)) } + case Modulo(a,b) => { + Ints.Mod(toSMT(a), toSMT(b)) + } case LessThan(a,b) => a.getType match { case Int32Type => FixedSizeBitVectors.SLessThan(toSMT(a), toSMT(b)) case IntegerType => Ints.LessThan(toSMT(a), toSMT(b)) @@ -677,7 +680,7 @@ abstract class SMTLIBSolver(val context: LeonContext, case BVMinus(a,b) => FixedSizeBitVectors.Sub(toSMT(a), toSMT(b)) case BVTimes(a,b) => FixedSizeBitVectors.Mul(toSMT(a), toSMT(b)) case BVDivision(a,b) => FixedSizeBitVectors.SDiv(toSMT(a), toSMT(b)) - case BVModulo(a,b) => FixedSizeBitVectors.SRem(toSMT(a), toSMT(b)) + case BVRemainder(a,b) => FixedSizeBitVectors.SRem(toSMT(a), toSMT(b)) case BVAnd(a,b) => FixedSizeBitVectors.And(toSMT(a), toSMT(b)) case BVOr(a,b) => FixedSizeBitVectors.Or(toSMT(a), toSMT(b)) case BVXOr(a,b) => FixedSizeBitVectors.XOr(toSMT(a), toSMT(b)) diff --git a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala index d8ac22b21b4f387077cd9f583f8958124da657cd..e036c86eba71fdd38cfeface511816fc0837e808 100644 --- a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala +++ b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala @@ -569,16 +569,19 @@ trait AbstractZ3Solver z3.mkUnaryMinus(z3.mkDiv(z3.mkUnaryMinus(rl), rr)) ) } - case Modulo(l, r) => { + case Remainder(l, r) => { val q = rec(Division(l, r)) z3.mkSub(rec(l), z3.mkMul(rec(r), q)) } + case Modulo(l, r) => { + z3.mkMod(rec(l), rec(r)) + } case UMinus(e) => z3.mkUnaryMinus(rec(e)) case BVPlus(l, r) => z3.mkBVAdd(rec(l), rec(r)) case BVMinus(l, r) => z3.mkBVSub(rec(l), rec(r)) case BVTimes(l, r) => z3.mkBVMul(rec(l), rec(r)) case BVDivision(l, r) => z3.mkBVSdiv(rec(l), rec(r)) - case BVModulo(l, r) => z3.mkBVSrem(rec(l), rec(r)) + case BVRemainder(l, r) => z3.mkBVSrem(rec(l), rec(r)) case BVUMinus(e) => z3.mkBVNeg(rec(e)) case BVNot(e) => z3.mkBVNot(rec(e)) case BVAnd(l, r) => z3.mkBVAnd(rec(l), rec(r)) diff --git a/src/test/scala/leon/test/evaluators/DefaultEvaluatorTests.scala b/src/test/scala/leon/test/evaluators/DefaultEvaluatorTests.scala index b4b4540cde7e86dcb04a8529c9d4d8927e4ba47d..ad359346a3e842df1cc621be793cfba3557dfde7 100644 --- a/src/test/scala/leon/test/evaluators/DefaultEvaluatorTests.scala +++ b/src/test/scala/leon/test/evaluators/DefaultEvaluatorTests.scala @@ -79,10 +79,13 @@ class DefaultEvaluatorTests extends leon.test.LeonTestSuite { InfiniteIntegerLiteral(6)) } - test("Eval of division and modulo semantics for BigInt") { + test("Eval of division, remainder and modulo semantics for BigInt") { expectSuccessful( defaultEvaluator.eval(Division(InfiniteIntegerLiteral(10), InfiniteIntegerLiteral(3))), InfiniteIntegerLiteral(3)) + expectSuccessful( + defaultEvaluator.eval(Remainder(InfiniteIntegerLiteral(10), InfiniteIntegerLiteral(3))), + InfiniteIntegerLiteral(1)) expectSuccessful( defaultEvaluator.eval(Modulo(InfiniteIntegerLiteral(10), InfiniteIntegerLiteral(3))), InfiniteIntegerLiteral(1)) @@ -91,51 +94,60 @@ class DefaultEvaluatorTests extends leon.test.LeonTestSuite { defaultEvaluator.eval(Division(InfiniteIntegerLiteral(-1), InfiniteIntegerLiteral(3))), InfiniteIntegerLiteral(0)) expectSuccessful( - defaultEvaluator.eval(Modulo(InfiniteIntegerLiteral(-1), InfiniteIntegerLiteral(3))), + defaultEvaluator.eval(Remainder(InfiniteIntegerLiteral(-1), InfiniteIntegerLiteral(3))), InfiniteIntegerLiteral(-1)) + expectSuccessful( + defaultEvaluator.eval(Modulo(InfiniteIntegerLiteral(-1), InfiniteIntegerLiteral(3))), + InfiniteIntegerLiteral(2)) expectSuccessful( defaultEvaluator.eval(Division(InfiniteIntegerLiteral(-1), InfiniteIntegerLiteral(-3))), InfiniteIntegerLiteral(0)) expectSuccessful( - defaultEvaluator.eval(Modulo(InfiniteIntegerLiteral(-1), InfiniteIntegerLiteral(-3))), + defaultEvaluator.eval(Remainder(InfiniteIntegerLiteral(-1), InfiniteIntegerLiteral(-3))), InfiniteIntegerLiteral(-1)) + expectSuccessful( + defaultEvaluator.eval(Modulo(InfiniteIntegerLiteral(-1), InfiniteIntegerLiteral(-3))), + InfiniteIntegerLiteral(2)) expectSuccessful( defaultEvaluator.eval(Division(InfiniteIntegerLiteral(1), InfiniteIntegerLiteral(-3))), InfiniteIntegerLiteral(0)) + expectSuccessful( + defaultEvaluator.eval(Remainder(InfiniteIntegerLiteral(1), InfiniteIntegerLiteral(-3))), + InfiniteIntegerLiteral(1)) expectSuccessful( defaultEvaluator.eval(Modulo(InfiniteIntegerLiteral(1), InfiniteIntegerLiteral(-3))), InfiniteIntegerLiteral(1)) } - test("Eval of division and modulo semantics for bit vectors") { + test("Eval of division and remainder semantics for bit vectors") { expectSuccessful( defaultEvaluator.eval(BVDivision(IntLiteral(10), IntLiteral(3))), IntLiteral(3)) expectSuccessful( - defaultEvaluator.eval(BVModulo(IntLiteral(10), IntLiteral(3))), + defaultEvaluator.eval(BVRemainder(IntLiteral(10), IntLiteral(3))), IntLiteral(1)) expectSuccessful( defaultEvaluator.eval(BVDivision(IntLiteral(-1), IntLiteral(3))), IntLiteral(0)) expectSuccessful( - defaultEvaluator.eval(BVModulo(IntLiteral(-1), IntLiteral(3))), + defaultEvaluator.eval(BVRemainder(IntLiteral(-1), IntLiteral(3))), IntLiteral(-1)) expectSuccessful( defaultEvaluator.eval(BVDivision(IntLiteral(-1), IntLiteral(-3))), IntLiteral(0)) expectSuccessful( - defaultEvaluator.eval(BVModulo(IntLiteral(-1), IntLiteral(-3))), + defaultEvaluator.eval(BVRemainder(IntLiteral(-1), IntLiteral(-3))), IntLiteral(-1)) expectSuccessful( defaultEvaluator.eval(BVDivision(IntLiteral(1), IntLiteral(-3))), IntLiteral(0)) expectSuccessful( - defaultEvaluator.eval(BVModulo(IntLiteral(1), IntLiteral(-3))), + defaultEvaluator.eval(BVRemainder(IntLiteral(1), IntLiteral(-3))), IntLiteral(1)) } diff --git a/src/test/scala/leon/test/evaluators/EvaluatorsTests.scala b/src/test/scala/leon/test/evaluators/EvaluatorsTests.scala index 20bd917324e4e481af824aa261162f359c56ed88..f34d82dee639a7052cfcb9adc314b0bf7f4c4a63 100644 --- a/src/test/scala/leon/test/evaluators/EvaluatorsTests.scala +++ b/src/test/scala/leon/test/evaluators/EvaluatorsTests.scala @@ -174,7 +174,7 @@ class EvaluatorsTests extends leon.test.LeonTestSuite { | if(s > n) c else intSqrt0(n, c+1) | } | def div(x : Int, y : Int) : Int = (x / y) - | def mod(x : Int, y : Int) : Int = (x % y) + | def rem(x : Int, y : Int) : Int = (x % y) |} |""".stripMargin @@ -191,15 +191,15 @@ class EvaluatorsTests extends leon.test.LeonTestSuite { checkComp(e, mkCall("div", IL(7), IL(-5)), IL(-1)) checkComp(e, mkCall("div", IL(-7), IL(5)), IL(-1)) checkComp(e, mkCall("div", IL(-7), IL(-5)), IL(1)) - checkComp(e, mkCall("mod", IL(7), IL(5)), IL(2)) - checkComp(e, mkCall("mod", IL(7), IL(-5)), IL(2)) - checkComp(e, mkCall("mod", IL(-7), IL(5)), IL(-2)) - checkComp(e, mkCall("mod", IL(-7), IL(-5)), IL(-2)) - checkComp(e, mkCall("mod", IL(-1), IL(5)), IL(-1)) + checkComp(e, mkCall("rem", IL(7), IL(5)), IL(2)) + checkComp(e, mkCall("rem", IL(7), IL(-5)), IL(2)) + checkComp(e, mkCall("rem", IL(-7), IL(5)), IL(-2)) + checkComp(e, mkCall("rem", IL(-7), IL(-5)), IL(-2)) + checkComp(e, mkCall("rem", IL(-1), IL(5)), IL(-1)) // Things that should crash. checkError(e, mkCall("div", IL(42), IL(0))) - checkError(e, mkCall("mod", IL(42), IL(0))) + checkError(e, mkCall("rem", IL(42), IL(0))) } } @@ -215,7 +215,8 @@ class EvaluatorsTests extends leon.test.LeonTestSuite { | if(s > n) c else intSqrt0(n, c+1) | } | def div(x : BigInt, y : BigInt) : BigInt = (x / y) - | def mod(x : BigInt, y : BigInt) : BigInt = (x % y) + | def rem(x : BigInt, y : BigInt) : BigInt = (x % y) + | def mod(x : BigInt, y : BigInt) : BigInt = (x mod y) |} |""".stripMargin @@ -232,14 +233,20 @@ class EvaluatorsTests extends leon.test.LeonTestSuite { checkComp(e, mkCall("div", BIL(7), BIL(-5)), BIL(-1)) checkComp(e, mkCall("div", BIL(-7), BIL(5)), BIL(-1)) checkComp(e, mkCall("div", BIL(-7), BIL(-5)), BIL(1)) + checkComp(e, mkCall("rem", BIL(7), BIL(5)), BIL(2)) + checkComp(e, mkCall("rem", BIL(7), BIL(-5)), BIL(2)) + checkComp(e, mkCall("rem", BIL(-7), BIL(5)), BIL(-2)) + checkComp(e, mkCall("rem", BIL(-7), BIL(-5)), BIL(-2)) + checkComp(e, mkCall("rem", BIL(-1), BIL(5)), BIL(-1)) checkComp(e, mkCall("mod", BIL(7), BIL(5)), BIL(2)) checkComp(e, mkCall("mod", BIL(7), BIL(-5)), BIL(2)) - checkComp(e, mkCall("mod", BIL(-7), BIL(5)), BIL(-2)) - checkComp(e, mkCall("mod", BIL(-7), BIL(-5)), BIL(-2)) - checkComp(e, mkCall("mod", BIL(-1), BIL(5)), BIL(-1)) + checkComp(e, mkCall("mod", BIL(-7), BIL(5)), BIL(3)) + checkComp(e, mkCall("mod", BIL(-7), BIL(-5)), BIL(3)) + checkComp(e, mkCall("mod", BIL(-1), BIL(5)), BIL(4)) // Things that should crash. checkError(e, mkCall("div", BIL(42), BIL(0))) + checkError(e, mkCall("rem", BIL(42), BIL(0))) checkError(e, mkCall("mod", BIL(42), BIL(0))) } }