Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
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("")
}
}
30 changes: 23 additions & 7 deletions libraries/common/effekt.effekt
Original file line number Diff line number Diff line change
Expand Up @@ -332,8 +332,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 +343,27 @@ 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)
q - (r.bitwiseShr(31).bitwiseAnd(y.bitwiseShr(31).bitwiseOr(1)))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stupid question: Will this work on LLVM where Int is i64 as opposed to f64 (~i32 for the purposes of bin ops) like in JS?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears to be working and yielding consistent results with the remaining backends. I'll do some further testing, though. Good point, thanks!

}

/// Computes the result of Euclidean modulo
def mod(x: Int, y: Int): Int = {
val r = x.rem(y)
r + y.abs.bitwiseAnd(r.bitwiseShr(31))
}

extern def infixAdd(x: Double, y: Double) at {}: Double =
js "(${x} + ${y})"
Expand Down
Loading