Skip to content

Commit

Permalink
Implement missing math functions in LLVM backend
Browse files Browse the repository at this point in the history
Implement cos, sin, atan, tan, log, log1p, _pi, exp & pow.
All functions use the LLVM intrinsics except tan & atan. They do not exist in the version of LLVM we are using.

Fixes #608
  • Loading branch information
mattisboeckle committed Dec 11, 2024
1 parent 92a6e0f commit 1dfcaf1
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 0 deletions.
9 changes: 9 additions & 0 deletions examples/pos/math.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
1
0
0
0
1
32
0
0
1
11 changes: 11 additions & 0 deletions examples/pos/math.effekt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
def main() = {
println(cos(0.0))
println(sin(0.0))
println(log(1.0))
println(log1p(0.0))
println(exp(0.0))
println(pow(2.0, 5.0))
println(tan(0.0))
println(atan(0.0))
println(sin(PI / 2.0))
}
18 changes: 18 additions & 0 deletions libraries/common/effekt.effekt
Original file line number Diff line number Diff line change
Expand Up @@ -320,18 +320,23 @@ extern pure def infixDiv(x: Double, y: Double): Double =
extern pure def cos(x: Double): Double =
js "Math.cos(${x})"
chez "(cos ${x})"
llvm "%z = call %Double @llvm.cos.f64(double ${x}) ret %Double %z"

extern pure def sin(x: Double): Double =
js "Math.sin(${x})"
chez "(sin ${x})"
llvm "%z = call %Double @llvm.sin.f64(double ${x}) ret %Double %z"

// We have to use the non-intrinsic versions of 'tan' & 'atan' as they were only added in LLVM 19
extern pure def atan(x: Double): Double =
js "Math.atan(${x})"
chez "(atan ${x})"
llvm "%z = call %Double @atan(double ${x}) ret %Double %z"

extern pure def tan(x: Double): Double =
js "Math.tan(${x})"
chez "(tan ${x})"
llvm "%z = call %Double @tan(double ${x}) ret %Double %z"

extern pure def sqrt(x: Double): Double =
js "Math.sqrt(${x})"
Expand All @@ -352,14 +357,20 @@ def abs(n: Double): Double =
extern pure def log(x: Double): Double =
js "Math.log(${x})"
chez "(log ${x})"
llvm "%z = call %Double @llvm.log.f64(double ${x}) ret %Double %z"

extern pure def log1p(x: Double): Double =
js "Math.log1p(${x})"
chez "(log (+ ${x} 1))"
llvm """
%i = fadd %Double 1.0, ${x}
%z = call %Double @llvm.log.f64(double %i) ret %Double %z
"""

extern pure def exp(x: Double): Double =
js "Math.exp(${x})"
chez "(exp ${x})"
llvm "%z = call %Double @llvm.exp.f64(double ${x}) ret %Double %z"

def pow(base: Double, exponent: Int): Double = {
def loop(base: Double, exponent: Int, acc: Double): Double = {
Expand All @@ -373,11 +384,18 @@ def pow(base: Double, exponent: Int): Double = {
extern pure def pow(base: Double, exponent: Double): Double =
js "Math.pow(${base}, ${exponent})"
chez "(expt ${base} ${exponent})"
llvm "%z = call %Double @llvm.pow.f64(double ${base}, double ${exponent}) ret %Double %z"

// since we do not have "extern val", yet
extern pure def _pi(): Double =
js "Math.PI"
chez "(* 4 (atan 1))"
// We have to use the non-intrinsic version of 'atan' as it was only added in LLVM 19
llvm """
%i = call %Double @atan(double 1.0)
%z = fmul %Double %i, 4.0
ret %Double %z
"""

val PI: Double = _pi()

Expand Down
8 changes: 8 additions & 0 deletions libraries/llvm/rts.ll
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,14 @@ declare double @llvm.sqrt.f64(double)
declare double @llvm.round.f64(double)
declare double @llvm.ceil.f64(double)
declare double @llvm.floor.f64(double)
declare double @llvm.cos.f64(double)
declare double @llvm.sin.f64(double)
declare double @llvm.log.f64(double)
declare double @llvm.exp.f64(double)
declare double @llvm.pow.f64(double, double)
; Intrinsic versions of the following two only added in LLVM 19
declare double @atan(double)
declare double @tan(double)
declare void @print(i64)
declare void @exit(i64)
declare void @llvm.assume(i1)
Expand Down

0 comments on commit 1dfcaf1

Please sign in to comment.