From 6dd72d8925b547f08c81c57001313269d61980e0 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Tue, 28 Apr 2026 08:36:43 +0200 Subject: [PATCH] compiler: use LLVM intrinsics for math trig operations I think this failed in the past, but presumably those failures have been fixed by now. So these intrinsics can now be used. Using these intrinsics instead of the native Go implementations helps LLVM to reason about them: it can for example evaluate the value at compile time or do optimizations like convert `float32(math.Sin(float64(x)))` into a 32-bit sin operation. If the math operation is not available on the target platform the C library implementation will be used instead. --- compiler/intrinsics.go | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/compiler/intrinsics.go b/compiler/intrinsics.go index e60d16ebf8..213bcb6799 100644 --- a/compiler/intrinsics.go +++ b/compiler/intrinsics.go @@ -166,13 +166,24 @@ func (b *builder) createMachineKeepAliveImpl() { } var mathToLLVMMapping = map[string]string{ - "math.Ceil": "llvm.ceil.f64", - "math.Exp": "llvm.exp.f64", - "math.Exp2": "llvm.exp2.f64", - "math.Floor": "llvm.floor.f64", - "math.Log": "llvm.log.f64", - "math.Sqrt": "llvm.sqrt.f64", - "math.Trunc": "llvm.trunc.f64", + "math.Acos": "llvm.acos.f64", + "math.Asin": "llvm.asin.f64", + "math.Atan": "llvm.atan.f64", + "math.Atan2": "llvm.atan2.f64", + "math.Ceil": "llvm.ceil.f64", + "math.Cos": "llvm.cos.f64", + "math.Cosh": "llvm.cosh.f64", + "math.Exp": "llvm.exp.f64", + "math.Exp2": "llvm.exp2.f64", + "math.Floor": "llvm.floor.f64", + "math.Log": "llvm.log.f64", + "math.Sin": "llvm.sin.f64", + "math.Sincos": "llvm.sincos.f64", + "math.Sinh": "llvm.sinh.f64", + "math.Sqrt": "llvm.sqrt.f64", + "math.Tan": "llvm.tan.f64", + "math.Tanh": "llvm.tanh.f64", + "math.Trunc": "llvm.trunc.f64", } // defineMathOp defines a math function body as a call to a LLVM intrinsic, @@ -194,9 +205,18 @@ func (b *builder) defineMathOp() { llvmFn := b.mod.NamedFunction(llvmName) if llvmFn.IsNil() { // The intrinsic doesn't exist yet, so declare it. - // At the moment, all supported intrinsics have the form "double - // foo(double %x)" so we can hardcode the signature here. - llvmType := llvm.FunctionType(b.ctx.DoubleType(), []llvm.Type{b.ctx.DoubleType()}, false) + var llvmType llvm.Type + switch b.fn.Name() { + case "Atan2": + // double atan2(double %y, double %x) + llvmType = llvm.FunctionType(b.ctx.DoubleType(), []llvm.Type{b.ctx.DoubleType(), b.ctx.DoubleType()}, false) + case "Sincos": + // {double, double} sincos(double %x) + llvmType = llvm.FunctionType(b.ctx.StructType([]llvm.Type{b.ctx.DoubleType(), b.ctx.DoubleType()}, false), []llvm.Type{b.ctx.DoubleType()}, false) + default: + // double foo(double %x) + llvmType = llvm.FunctionType(b.ctx.DoubleType(), []llvm.Type{b.ctx.DoubleType()}, false) + } llvmFn = llvm.AddFunction(b.mod, llvmName, llvmType) } // Create a call to the intrinsic.