Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion effekt/shared/src/main/scala/effekt/core/vm/Builtin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,30 @@ lazy val integers: Builtins = Map(
builtin("effekt::infixMul(Int, Int)") {
case As.Int(x) :: As.Int(y) :: Nil => Value.Int(x * y)
},
builtin("effekt::rem(Int, Int)") {
case As.Int(x) :: As.Int(y) :: Nil => Value.Int(x - y * (x / y))
},
builtin("effekt::quot(Int, Int)") {
case As.Int(x) :: As.Int(y) :: Nil => Value.Int(x / y)
},
builtin("effekt::div(Int, Int)") {
case As.Int(x) :: As.Int(y) :: Nil =>
val q = x / y
val r = x - y * (x / y)
if (r < 0) {
Value.Int(q - y.sign)
} else {
Value.Int(q)
}
},
builtin("effekt::mod(Int, Int)") {
case As.Int(x) :: As.Int(y) :: Nil => Value.Int(x % y)
case As.Int(x) :: As.Int(y) :: Nil =>
val r = x - y * (x / y)
if (r < 0) {
Value.Int(r + y.abs)
} else {
Value.Int(r)
}
},
builtin("effekt::infixDiv(Int, Int)") {
case As.Int(x) :: As.Int(y) :: Nil => Value.Int(x / y)
Expand All @@ -150,6 +172,9 @@ lazy val integers: Builtins = Map(
builtin("effekt::bitwiseXor(Int, Int)") {
case As.Int(x) :: As.Int(y) :: Nil => Value.Int(x ^ y)
},
builtin("effekt::bitwiseMsb(Int)") {
case As.Int(x) :: Nil => Value.Int(x >> 63)
},

// Comparison
// ----------
Expand Down
10 changes: 10 additions & 0 deletions examples/stdlib/mod.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
8 `divmod` 3 = 2, 2
8 `divmod` -3 = -2, 2
-8 `divmod` 3 = -3, 1
-8 `divmod` -3 = 3, 1

8 `quotrem` 3 = 2, 2
8 `quotrem` -3 = -2, 2
-8 `quotrem` 3 = -2, -2
-8 `quotrem` -3 = 2, -2

15 changes: 15 additions & 0 deletions examples/stdlib/mod.effekt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
def main() = {
val ops = [
(box { (x: Int, y: Int) => (x.div(y), x.mod(y), x == y * x.div(y) + x.mod(y)) }, "divmod"),
(box { (x: Int, y: Int) => (x.quot(y), x.rem(y), x == y * x.quot(y) + x.rem(y)) }, "quotrem"),
]
ops.foreach { case (op, name) =>
[8, 8.neg].foreach { dividend =>
[3, 3.neg].foreach { divisor =>
val (q, r, assertion) = op(dividend, divisor)
println(s"${dividend.show} `${name}` ${divisor.show} = ${q.show}, ${r.show}")
}
}
println("")
}
}
45 changes: 38 additions & 7 deletions libraries/common/effekt.effekt
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,12 @@ extern def infixNeq(x: Bool, y: Bool) at {}: Bool =

// Math ops
// ========

// Numeric representations in the backends:
// LLVM: int64_t (64-bit integer)
// JS: 64-bit floating-point (64-bit IEEE 754)
// Chez: 64-bit integer

extern def infixAdd(x: Int, y: Int) at {}: Int =
js "(${x} + ${y})"
chez "(+ ${x} ${y})"
Expand All @@ -332,8 +338,8 @@ extern def infixMul(x: Int, y: Int) at {}: Int =
vm "effekt::infixMul(Int, Int)"

extern def infixDiv(x: Int, y: Int) at {}: Int =
js "Math.floor(${x} / ${y})"
chez "(floor (/ ${x} ${y}))"
js "Math.trunc(${x} / ${y})"
chez "(truncate (/ ${x} ${y}))"
llvm "%z = sdiv %Int ${x}, ${y} ret %Int %z"
vm "effekt::infixDiv(Int, Int)"

Expand All @@ -343,11 +349,31 @@ extern def infixSub(x: Int, y: Int) at {}: Int =
llvm "%z = sub %Int ${x}, ${y} ret %Int %z"
vm "effekt::infixSub(Int, Int)"

extern def mod(x: Int, y: Int) at {}: Int =
js "(${x} % ${y})"
chez "(modulo ${x} ${y})"
llvm "%z = srem %Int ${x}, ${y} ret %Int %z"
vm "effekt::mod(Int, Int)"
/// Computes the quotient based on truncated-division
def quot(x: Int, y: Int): Int =
infixDiv(x, y)

/// Computes the remainder based on truncated-division
extern def rem(x: Int, y: Int) at {}: Int =
llvm "%z = srem %Int ${x}, ${y} ret %Int %z"
default { x - y * (x / y) }

/// Computes the result of Euclidean division
def div(x: Int, y: Int): Int = {
val q = x / y
val r = x.rem(y)
val rNeg = r.bitwiseMsb
val ySign = y.bitwiseMsb.bitwiseOr(1)
q - rNeg.bitwiseAnd(ySign)
}

/// Computes the result of Euclidean modulo
def mod(x: Int, y: Int): Int = {
val r = x.rem(y)
val rNeg = r.bitwiseMsb
val absY = y.bitwiseXor(y.bitwiseMsb) - y.bitwiseMsb
r + rNeg.bitwiseAnd(absY)
}

extern def infixAdd(x: Double, y: Double) at {}: Double =
js "(${x} + ${y})"
Expand Down Expand Up @@ -677,6 +703,11 @@ extern def bitwiseXor(x: Int, y: Int) at {}: Int =
llvm "%z = xor %Int ${x}, ${y} ret %Int %z"
vm "effekt::bitwiseXor(Int, Int)"

extern def bitwiseMsb(x: Int) at {}: Int =
js "${x} >> 31"
chez "(bitwise-arithmetic-shift-right ${x} 63)"
llvm "%z = ashr %Int ${x}, 63 ret %Int %z"
vm "effekt::bitwiseMsb(Int)"

// Byte operations
// ===============
Expand Down
Loading