diff --git a/README.md b/README.md index b2ee0dab..eb52c41e 100644 --- a/README.md +++ b/README.md @@ -206,8 +206,9 @@ Here are the Go packages that can be imported correctly: * [unicode](https://pkg.go.dev/unicode) * [unicode/utf8](https://pkg.go.dev/unicode/utf8) * [unicode/utf16](https://pkg.go.dev/unicode/utf16) -* [math/bits](https://pkg.go.dev/math/bits) * [math](https://pkg.go.dev/math) +* [math/bits](https://pkg.go.dev/math/bits) +* [math/cmplx](https://pkg.go.dev/math/cmplx) * [syscall](https://pkg.go.dev/syscall) (partially) * [sync](https://pkg.go.dev/sync) (partially) * [sync/atomic](https://pkg.go.dev/sync/atomic) (partially) @@ -217,8 +218,8 @@ Here are the Go packages that can be imported correctly: - [Go 1.20+](https://go.dev) (build only) - [LLVM 17](https://llvm.org) -- [Clang 17](https://clang.llvm.org) - [LLD 17](https://lld.llvm.org) +- [Clang 17](https://clang.llvm.org) - [pkg-config 0.29+](https://www.freedesktop.org/wiki/Software/pkg-config/) - [bdwgc/libgc 8.0+](https://www.hboehm.info/gc/) - [cJSON 1.7+](https://github.com/DaveGamble/cJSON) (optional, for [`github.com/goplus/llgo/c/cjson`](https://pkg.go.dev/github.com/goplus/llgo/c/cjson)) diff --git a/_demo/complex/cmplx.go b/_demo/complex/cmplx.go new file mode 100644 index 00000000..7610e171 --- /dev/null +++ b/_demo/complex/cmplx.go @@ -0,0 +1,9 @@ +package main + +import ( + "math/cmplx" +) + +func main() { + println("abs(3+4i):", cmplx.Abs(3+4i)) +} diff --git a/c/math/cmplx/complex.go b/c/math/cmplx/complex.go new file mode 100644 index 00000000..c24a276e --- /dev/null +++ b/c/math/cmplx/complex.go @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cmplx + +import ( + _ "unsafe" +) + +const ( + LLGoPackage = "decl" +) + +// ----------------------------------------------------------------------------- + +//go:linkname Abs C.cabs +func Abs(z complex128) float64 + +//go:linkname Acos C.cacos +func Acos(z complex128) complex128 + +//go:linkname Acosh C.cacosh +func Acosh(z complex128) complex128 + +//go:linkname Asin C.casin +func Asin(z complex128) complex128 + +//go:linkname Asinh C.casinh +func Asinh(z complex128) complex128 + +//go:linkname Atan C.catan +func Atan(z complex128) complex128 + +//go:linkname Atanh C.catanh +func Atanh(z complex128) complex128 + +//go:linkname Cos C.ccos +func Cos(z complex128) complex128 + +//go:linkname Cosh C.ccosh +func Cosh(z complex128) complex128 + +//go:linkname Exp C.cexp +func Exp(z complex128) complex128 + +//go:linkname Log C.clog +func Log(z complex128) complex128 + +//go:linkname Log10 C.clog10 +func Log10(z complex128) complex128 + +//go:linkname Arg C.carg +func Arg(z complex128) float64 + +//go:linkname Phase C.carg +func Phase(z complex128) float64 + +//go:linkname Pow C.cpow +func Pow(x, y complex128) complex128 + +//go:linkname Sin C.csin +func Sin(z complex128) complex128 + +//go:linkname Sinh C.csinh +func Sinh(z complex128) complex128 + +//go:linkname Sqrt C.csqrt +func Sqrt(z complex128) complex128 + +//go:linkname Tan C.ctan +func Tan(z complex128) complex128 + +//go:linkname Tanh C.ctanh +func Tanh(z complex128) complex128 + +// ----------------------------------------------------------------------------- diff --git a/internal/build/build.go b/internal/build/build.go index eec95fe1..ad28295b 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -722,6 +722,7 @@ var hasAltPkg = map[string]none{ "io": {}, "io/fs": {}, "math": {}, + "math/cmplx": {}, "sync": {}, "sync/atomic": {}, "syscall": {}, diff --git a/internal/lib/math/cmplx/cmplx.go b/internal/lib/math/cmplx/cmplx.go new file mode 100644 index 00000000..649909b5 --- /dev/null +++ b/internal/lib/math/cmplx/cmplx.go @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cmplx + +import ( + _ "unsafe" +) + +const ( + LLGoPackage = true +) + +// ----------------------------------------------------------------------------- + +//go:linkname Abs C.cabs +func Abs(z complex128) float64 + +//go:linkname Acos C.cacos +func Acos(z complex128) complex128 + +//go:linkname Acosh C.cacosh +func Acosh(z complex128) complex128 + +//go:linkname Asin C.casin +func Asin(z complex128) complex128 + +//go:linkname Asinh C.casinh +func Asinh(z complex128) complex128 + +//go:linkname Atan C.catan +func Atan(z complex128) complex128 + +//go:linkname Atanh C.catanh +func Atanh(z complex128) complex128 + +//go:linkname Cos C.ccos +func Cos(z complex128) complex128 + +//go:linkname Cosh C.ccosh +func Cosh(z complex128) complex128 + +//go:linkname Exp C.cexp +func Exp(z complex128) complex128 + +//go:linkname Log C.clog +func Log(z complex128) complex128 + +//go:linkname Log10 C.clog10 +func Log10(z complex128) complex128 + +//go:linkname Phase C.carg +func Phase(z complex128) float64 + +//go:linkname Pow C.cpow +func Pow(x, y complex128) complex128 + +//go:linkname Sin C.csin +func Sin(z complex128) complex128 + +//go:linkname Sinh C.csinh +func Sinh(z complex128) complex128 + +//go:linkname Sqrt C.csqrt +func Sqrt(z complex128) complex128 + +//go:linkname Tan C.ctan +func Tan(z complex128) complex128 + +//go:linkname Tanh C.ctanh +func Tanh(z complex128) complex128 + +// ----------------------------------------------------------------------------- diff --git a/ssa/datastruct.go b/ssa/datastruct.go index aba66b9d..82706e0a 100644 --- a/ssa/datastruct.go +++ b/ssa/datastruct.go @@ -66,6 +66,21 @@ func (b Builder) getField(x Expr, idx int) Expr { // ----------------------------------------------------------------------------- +func (b Builder) Complex(r, i Expr) Expr { + if debugInstr { + log.Printf("Complex %v, %v\n", r.impl, i.impl) + } + prog := b.Prog + var t Type + switch kind := r.raw.Type.Underlying().(*types.Basic).Kind(); kind { + case types.Float64: + t = prog.Complex128() + case types.Float32: + t = prog.Complex64() + } + return b.aggregateValue(t, r.impl, i.impl) +} + // MakeString creates a new string from a C string pointer and length. func (b Builder) MakeString(cstr Expr, n ...Expr) (ret Expr) { if debugInstr { diff --git a/ssa/expr.go b/ssa/expr.go index 7dbeb4fa..a9d9d1aa 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -168,11 +168,20 @@ func (p Program) IntVal(v uint64, t Type) Expr { return Expr{ret, t} } +// FloatVal returns a float constant expression. func (p Program) FloatVal(v float64, t Type) Expr { ret := llvm.ConstFloat(t.ll, v) return Expr{ret, t} } +// ComplexVal returns a complex constant expression. +func (p Program) ComplexVal(v complex128, t Type) Expr { + flt := p.Field(t, 0) + re := p.FloatVal(real(v), flt) + im := p.FloatVal(imag(v), flt) + return Expr{llvm.ConstStruct([]llvm.Value{re.impl, im.impl}, false), t} +} + // Val returns a constant expression. func (p Program) Val(v interface{}) Expr { switch v := v.(type) { @@ -211,11 +220,16 @@ func (b Builder) Const(v constant.Value, typ Type) Expr { if v, exact := constant.Uint64Val(v); exact { return prog.IntVal(v, typ) } - case kind == types.Float32 || kind == types.Float64: + case kind == types.Float64 || kind == types.Float32: v, _ := constant.Float64Val(v) return prog.FloatVal(v, typ) case kind == types.String: return Expr{b.Str(constant.StringVal(v)).impl, typ} + case kind == types.Complex128 || kind == types.Complex64: + v = constant.ToComplex(v) + re, _ := constant.Float64Val(constant.Real(v)) + im, _ := constant.Float64Val(constant.Imag(v)) + return prog.ComplexVal(complex(re, im), typ) } } panic(fmt.Sprintf("unsupported Const: %v, %v", v, raw)) @@ -941,6 +955,12 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) { return b.Recover() case "print", "println": return b.PrintEx(fn == "println", args...) + case "complex": + return b.Complex(args[0], args[1]) + case "real": + return b.getField(args[0], 0) + case "imag": + return b.getField(args[0], 1) case "String": // unsafe.String return b.unsafeString(args[0].impl, args[1].impl) case "Slice": // unsafe.Slice diff --git a/ssa/package.go b/ssa/package.go index 2a04994f..54f6484f 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -125,15 +125,16 @@ type aProgram struct { voidType llvm.Type voidPtrTy llvm.Type + c64Type llvm.Type + c128Type llvm.Type + rtStringTy llvm.Type rtEfaceTy llvm.Type rtIfaceTy llvm.Type rtSliceTy llvm.Type rtMapTy llvm.Type - anyTy Type - //anyPtr Type - //anyPPtr Type + anyTy Type voidTy Type voidPtr Type voidPPtr Type @@ -147,6 +148,8 @@ type aProgram struct { uintTy Type f64Ty Type f32Ty Type + c128Ty Type + c64Ty Type byteTy Type i32Ty Type u32Ty Type @@ -284,6 +287,24 @@ func (p Program) rtString() llvm.Type { return p.rtStringTy } +func (p Program) tyComplex64() llvm.Type { + if p.c64Type.IsNil() { + ctx := p.ctx + f32 := ctx.FloatType() + p.c64Type = ctx.StructType([]llvm.Type{f32, f32}, false) + } + return p.c64Type +} + +func (p Program) tyComplex128() llvm.Type { + if p.c128Type.IsNil() { + ctx := p.ctx + f64 := ctx.DoubleType() + p.c128Type = ctx.StructType([]llvm.Type{f64, f64}, false) + } + return p.c128Type +} + // NewPackage creates a new package. func (p Program) NewPackage(name, pkgPath string) Package { mod := p.ctx.NewModule(pkgPath) @@ -394,24 +415,6 @@ func (p Program) String() Type { return p.stringTy } -/* -// AnyPtrPtr returns **any type. -func (p Program) AnyPtrPtr() Type { - if p.anyPPtr == nil { - p.anyPPtr = p.Pointer(p.AnyPtr()) - } - return p.anyPPtr -} - -// AnyPtr returns *any type. -func (p Program) AnyPtr() Type { - if p.anyPtr == nil { - p.anyPtr = p.Pointer(p.Any()) - } - return p.anyPtr -} -*/ - // Any returns the any (empty interface) type. func (p Program) Any() Type { if p.anyTy == nil { @@ -484,6 +487,22 @@ func (p Program) Float32() Type { return p.f32Ty } +// Complex128 returns complex128 type. +func (p Program) Complex128() Type { + if p.c128Ty == nil { + p.c128Ty = p.rawType(types.Typ[types.Complex128]) + } + return p.c128Ty +} + +// Complex64 returns complex64 type. +func (p Program) Complex64() Type { + if p.c64Ty == nil { + p.c64Ty = p.rawType(types.Typ[types.Complex64]) + } + return p.c64Ty +} + // Byte returns byte type. func (p Program) Byte() Type { if p.byteTy == nil { diff --git a/ssa/type.go b/ssa/type.go index 9ee05e18..cc192ad5 100644 --- a/ssa/type.go +++ b/ssa/type.go @@ -214,6 +214,14 @@ func (p Program) Field(typ Type, i int) Type { switch t := typ.raw.Type.(type) { case *types.Tuple: fld = t.At(i) + case *types.Basic: + switch t.Kind() { + case types.Complex128: + return p.Float64() + case types.Complex64: + return p.Float32() + } + panic("Field: basic type doesn't have fields") default: fld = t.Underlying().(*types.Struct).Field(i) } @@ -330,7 +338,9 @@ func (p Program) toType(raw types.Type) Type { case types.Float64: return &aType{p.ctx.DoubleType(), typ, vkFloat} case types.Complex64: + return &aType{p.tyComplex64(), typ, vkComplex} case types.Complex128: + return &aType{p.tyComplex128(), typ, vkComplex} case types.String: return &aType{p.rtString(), typ, vkString} case types.UnsafePointer: