Merge pull request #368 from xushiwei/q

builtin: real/imag/complex; c/math/cmplx; patch: math/cmplx
This commit is contained in:
xushiwei
2024-06-20 10:31:24 +08:00
committed by GitHub
14 changed files with 484 additions and 24 deletions

View File

@@ -206,8 +206,9 @@ Here are the Go packages that can be imported correctly:
* [unicode](https://pkg.go.dev/unicode) * [unicode](https://pkg.go.dev/unicode)
* [unicode/utf8](https://pkg.go.dev/unicode/utf8) * [unicode/utf8](https://pkg.go.dev/unicode/utf8)
* [unicode/utf16](https://pkg.go.dev/unicode/utf16) * [unicode/utf16](https://pkg.go.dev/unicode/utf16)
* [math/bits](https://pkg.go.dev/math/bits)
* [math](https://pkg.go.dev/math) * [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) * [syscall](https://pkg.go.dev/syscall) (partially)
* [sync](https://pkg.go.dev/sync) (partially) * [sync](https://pkg.go.dev/sync) (partially)
* [sync/atomic](https://pkg.go.dev/sync/atomic) (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) - [Go 1.20+](https://go.dev) (build only)
- [LLVM 17](https://llvm.org) - [LLVM 17](https://llvm.org)
- [Clang 17](https://clang.llvm.org)
- [LLD 17](https://lld.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/) - [pkg-config 0.29+](https://www.freedesktop.org/wiki/Software/pkg-config/)
- [bdwgc/libgc 8.0+](https://www.hboehm.info/gc/) - [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)) - [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))

9
_demo/complex/cmplx.go Normal file
View File

@@ -0,0 +1,9 @@
package main
import (
"math/cmplx"
)
func main() {
println("abs(3+4i):", cmplx.Abs(3+4i))
}

151
c/math/cmplx/complex.go Normal file
View File

@@ -0,0 +1,151 @@
/*
* 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
// -----------------------------------------------------------------------------
//go:linkname Absf C.cabsf
func Absf(z complex64) float32
//go:linkname Acosf C.cacosf
func Acosf(z complex64) complex64
//go:linkname Acoshf C.cacoshf
func Acoshf(z complex64) complex64
//go:linkname Asinf C.casinf
func Asinf(z complex64) complex64
//go:linkname Asinhf C.casinhf
func Asinhf(z complex64) complex64
//go:linkname Atanf C.catanf
func Atanf(z complex64) complex64
//go:linkname Atanhf C.catanhf
func Atanhf(z complex64) complex64
//go:linkname Cosf C.ccosf
func Cosf(z complex64) complex64
//go:linkname Coshf C.ccoshf
func Coshf(z complex64) complex64
//go:linkname Expf C.cexpf
func Expf(z complex64) complex64
//go:linkname Logf C.clogf
func Logf(z complex64) complex64
//go:linkname Log10f C.clog10f
func Log10f(z complex64) complex64
//go:linkname Argf C.cargf
func Argf(z complex64) float32
//go:linkname Phasef C.cargf
func Phasef(z complex64) float32
//go:linkname Powf C.cpowf
func Powf(x, y complex64) complex64
//go:linkname Sinf C.csinf
func Sinf(z complex64) complex64
//go:linkname Sinhf C.csinhf
func Sinhf(z complex64) complex64
//go:linkname Sqrtf C.csqrtf
func Sqrtf(z complex64) complex64
//go:linkname Tanf C.ctanf
func Tanf(z complex64) complex64
//go:linkname Tanhf C.ctanhf
func Tanhf(z complex64) complex64
// -----------------------------------------------------------------------------

View File

@@ -0,0 +1,12 @@
package main
import (
"github.com/goplus/llgo/c/math/cmplx"
)
func main() {
re := float32(3.0)
im := float32(4.0)
c := complex(re, im)
println("abs(3+4i):", cmplx.Absf(c))
}

View File

@@ -0,0 +1,59 @@
; ModuleID = 'main'
source_filename = "main"
%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 }
@"main.init$guard" = global i1 false, align 1
@__llgo_argc = global i32 0, align 4
@__llgo_argv = global ptr null, align 8
@0 = private unnamed_addr constant [10 x i8] c"abs(3+4i):", align 1
define void @main.init() {
_llgo_0:
%0 = load i1, ptr @"main.init$guard", align 1
br i1 %0, label %_llgo_2, label %_llgo_1
_llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
define i32 @main(i32 %0, ptr %1) {
_llgo_0:
store i32 %0, ptr @__llgo_argc, align 4
store ptr %1, ptr @__llgo_argv, align 8
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init()
%2 = alloca { float, float }, align 8
%3 = getelementptr inbounds { float, float }, ptr %2, i32 0, i32 0
store float 3.000000e+00, ptr %3, align 4
%4 = getelementptr inbounds { float, float }, ptr %2, i32 0, i32 1
store float 4.000000e+00, ptr %4, align 4
%5 = load { float, float }, ptr %2, align 4
%6 = call float @cabsf({ float, float } %5)
%7 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%8 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %7, i32 0, i32 0
store ptr @0, ptr %8, align 8
%9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %7, i32 0, i32 1
store i64 10, ptr %9, align 4
%10 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %7, align 8
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %10)
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
%11 = fpext float %6 to double
call void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double %11)
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
ret i32 0
}
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare float @cabsf({ float, float })
declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String")
declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8)
declare void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double)

View File

@@ -0,0 +1,12 @@
package main
import (
"math/cmplx"
)
func main() {
re := 3.0
im := 4.0
c := complex(re, im)
println("abs(3+4i):", cmplx.Abs(c))
}

View File

@@ -0,0 +1,61 @@
; ModuleID = 'main'
source_filename = "main"
%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 }
@"main.init$guard" = global i1 false, align 1
@__llgo_argc = global i32 0, align 4
@__llgo_argv = global ptr null, align 8
@0 = private unnamed_addr constant [10 x i8] c"abs(3+4i):", align 1
define void @main.init() {
_llgo_0:
%0 = load i1, ptr @"main.init$guard", align 1
br i1 %0, label %_llgo_2, label %_llgo_1
_llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1
call void @"math/cmplx.init"()
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
define i32 @main(i32 %0, ptr %1) {
_llgo_0:
store i32 %0, ptr @__llgo_argc, align 4
store ptr %1, ptr @__llgo_argv, align 8
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init()
%2 = alloca { double, double }, align 8
%3 = getelementptr inbounds { double, double }, ptr %2, i32 0, i32 0
store double 3.000000e+00, ptr %3, align 8
%4 = getelementptr inbounds { double, double }, ptr %2, i32 0, i32 1
store double 4.000000e+00, ptr %4, align 8
%5 = load { double, double }, ptr %2, align 8
%6 = call double @"math/cmplx.Abs"({ double, double } %5)
%7 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%8 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %7, i32 0, i32 0
store ptr @0, ptr %8, align 8
%9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %7, i32 0, i32 1
store i64 10, ptr %9, align 4
%10 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %7, align 8
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %10)
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
call void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double %6)
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
ret i32 0
}
declare void @"math/cmplx.init"()
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare double @"math/cmplx.Abs"({ double, double })
declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String")
declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8)
declare void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double)

View File

@@ -742,6 +742,7 @@ var hasAltPkg = map[string]none{
"io": {}, "io": {},
"io/fs": {}, "io/fs": {},
"math": {}, "math": {},
"math/cmplx": {},
"sync": {}, "sync": {},
"sync/atomic": {}, "sync/atomic": {},
"syscall": {}, "syscall": {},

View File

@@ -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
// -----------------------------------------------------------------------------

View File

@@ -29,6 +29,10 @@ func init() {
ssa.SetDebug(ssa.DbgFlagAll) ssa.SetDebug(ssa.DbgFlagAll)
} }
func TestFromTestlibgo(t *testing.T) {
cltest.FromDir(t, "", "../cl/_testlibgo", false)
}
func TestFromTestgo(t *testing.T) { func TestFromTestgo(t *testing.T) {
cltest.FromDir(t, "", "../cl/_testgo", false) cltest.FromDir(t, "", "../cl/_testgo", false)
} }

View File

@@ -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. // MakeString creates a new string from a C string pointer and length.
func (b Builder) MakeString(cstr Expr, n ...Expr) (ret Expr) { func (b Builder) MakeString(cstr Expr, n ...Expr) (ret Expr) {
if debugInstr { if debugInstr {

View File

@@ -168,11 +168,20 @@ func (p Program) IntVal(v uint64, t Type) Expr {
return Expr{ret, t} return Expr{ret, t}
} }
// FloatVal returns a float constant expression.
func (p Program) FloatVal(v float64, t Type) Expr { func (p Program) FloatVal(v float64, t Type) Expr {
ret := llvm.ConstFloat(t.ll, v) ret := llvm.ConstFloat(t.ll, v)
return Expr{ret, t} 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. // Val returns a constant expression.
func (p Program) Val(v interface{}) Expr { func (p Program) Val(v interface{}) Expr {
switch v := v.(type) { 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 { if v, exact := constant.Uint64Val(v); exact {
return prog.IntVal(v, typ) return prog.IntVal(v, typ)
} }
case kind == types.Float32 || kind == types.Float64: case kind == types.Float64 || kind == types.Float32:
v, _ := constant.Float64Val(v) v, _ := constant.Float64Val(v)
return prog.FloatVal(v, typ) return prog.FloatVal(v, typ)
case kind == types.String: case kind == types.String:
return Expr{b.Str(constant.StringVal(v)).impl, typ} 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)) 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() return b.Recover()
case "print", "println": case "print", "println":
return b.PrintEx(fn == "println", args...) 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 case "String": // unsafe.String
return b.unsafeString(args[0].impl, args[1].impl) return b.unsafeString(args[0].impl, args[1].impl)
case "Slice": // unsafe.Slice case "Slice": // unsafe.Slice

View File

@@ -125,15 +125,16 @@ type aProgram struct {
voidType llvm.Type voidType llvm.Type
voidPtrTy llvm.Type voidPtrTy llvm.Type
c64Type llvm.Type
c128Type llvm.Type
rtStringTy llvm.Type rtStringTy llvm.Type
rtEfaceTy llvm.Type rtEfaceTy llvm.Type
rtIfaceTy llvm.Type rtIfaceTy llvm.Type
rtSliceTy llvm.Type rtSliceTy llvm.Type
rtMapTy llvm.Type rtMapTy llvm.Type
anyTy Type anyTy Type
//anyPtr Type
//anyPPtr Type
voidTy Type voidTy Type
voidPtr Type voidPtr Type
voidPPtr Type voidPPtr Type
@@ -147,6 +148,8 @@ type aProgram struct {
uintTy Type uintTy Type
f64Ty Type f64Ty Type
f32Ty Type f32Ty Type
c128Ty Type
c64Ty Type
byteTy Type byteTy Type
i32Ty Type i32Ty Type
u32Ty Type u32Ty Type
@@ -284,6 +287,24 @@ func (p Program) rtString() llvm.Type {
return p.rtStringTy 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. // NewPackage creates a new package.
func (p Program) NewPackage(name, pkgPath string) Package { func (p Program) NewPackage(name, pkgPath string) Package {
mod := p.ctx.NewModule(pkgPath) mod := p.ctx.NewModule(pkgPath)
@@ -394,24 +415,6 @@ func (p Program) String() Type {
return p.stringTy 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. // Any returns the any (empty interface) type.
func (p Program) Any() Type { func (p Program) Any() Type {
if p.anyTy == nil { if p.anyTy == nil {
@@ -484,6 +487,22 @@ func (p Program) Float32() Type {
return p.f32Ty 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. // Byte returns byte type.
func (p Program) Byte() Type { func (p Program) Byte() Type {
if p.byteTy == nil { if p.byteTy == nil {

View File

@@ -214,6 +214,14 @@ func (p Program) Field(typ Type, i int) Type {
switch t := typ.raw.Type.(type) { switch t := typ.raw.Type.(type) {
case *types.Tuple: case *types.Tuple:
fld = t.At(i) 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: default:
fld = t.Underlying().(*types.Struct).Field(i) fld = t.Underlying().(*types.Struct).Field(i)
} }
@@ -330,7 +338,9 @@ func (p Program) toType(raw types.Type) Type {
case types.Float64: case types.Float64:
return &aType{p.ctx.DoubleType(), typ, vkFloat} return &aType{p.ctx.DoubleType(), typ, vkFloat}
case types.Complex64: case types.Complex64:
return &aType{p.tyComplex64(), typ, vkComplex}
case types.Complex128: case types.Complex128:
return &aType{p.tyComplex128(), typ, vkComplex}
case types.String: case types.String:
return &aType{p.rtString(), typ, vkString} return &aType{p.rtString(), typ, vkString}
case types.UnsafePointer: case types.UnsafePointer: