Merge pull request #321 from xushiwei/q
patches of a standard library; testlibgo: math
This commit is contained in:
5
.github/workflows/go.yml
vendored
5
.github/workflows/go.yml
vendored
@@ -53,10 +53,11 @@ jobs:
|
|||||||
run: go build -v ./...
|
run: go build -v ./...
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
if: matrix.os != 'ubuntu-latest'
|
if: matrix.os != 'macos-latest'
|
||||||
run: go test -v ./...
|
run: go test -v ./...
|
||||||
|
|
||||||
- name: Test with coverage
|
- name: Test with coverage
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'macos-latest'
|
||||||
run: go test -v -coverprofile="coverage.txt" -covermode=atomic ./...
|
run: go test -v -coverprofile="coverage.txt" -covermode=atomic ./...
|
||||||
|
|
||||||
- name: Install
|
- name: Install
|
||||||
|
|||||||
@@ -207,6 +207,7 @@ Here are the Go packages that can be imported correctly:
|
|||||||
* [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/bits](https://pkg.go.dev/math/bits)
|
||||||
|
* [math](https://pkg.go.dev/math)
|
||||||
|
|
||||||
|
|
||||||
## How to install
|
## How to install
|
||||||
|
|||||||
11
_demo/math/math.go
Normal file
11
_demo/math/math.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
println(math.Sqrt(2))
|
||||||
|
println(math.Abs(-1.2))
|
||||||
|
println(math.Ldexp(1.2, 3))
|
||||||
|
}
|
||||||
@@ -149,9 +149,6 @@ func Nextafter(x, y float64) float64
|
|||||||
//go:linkname Pow C.pow
|
//go:linkname Pow C.pow
|
||||||
func Pow(x, y float64) float64
|
func Pow(x, y float64) float64
|
||||||
|
|
||||||
//go:linkname Pow10 C.pow10
|
|
||||||
func Pow10(x c.Int) float64
|
|
||||||
|
|
||||||
//go:linkname Remainder C.remainder
|
//go:linkname Remainder C.remainder
|
||||||
func Remainder(x, y float64) float64
|
func Remainder(x, y float64) float64
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -5,5 +5,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
println(math.Sqrt(2))
|
||||||
println(math.Abs(-1.2))
|
println(math.Abs(-1.2))
|
||||||
|
println(math.Ldexp(1.2, 3))
|
||||||
}
|
}
|
||||||
52
cl/_testlibgo/math/out.ll
Normal file
52
cl/_testlibgo/math/out.ll
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
; ModuleID = 'main'
|
||||||
|
source_filename = "main"
|
||||||
|
|
||||||
|
@"main.init$guard" = global i1 false, align 1
|
||||||
|
@__llgo_argc = global i32 0, align 4
|
||||||
|
@__llgo_argv = global ptr null, align 8
|
||||||
|
|
||||||
|
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.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 = call double @math.Sqrt(double 2.000000e+00)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double %2)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||||
|
%3 = call double @math.Abs(double -1.200000e+00)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double %3)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||||
|
%4 = call double @math.Ldexp(double 1.200000e+00, i64 3)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double %4)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||||
|
ret i32 0
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @math.init()
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||||
|
|
||||||
|
declare double @math.Sqrt(double)
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/internal/runtime.PrintFloat"(double)
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8)
|
||||||
|
|
||||||
|
declare double @math.Abs(double)
|
||||||
|
|
||||||
|
declare double @math.Ldexp(double, i64)
|
||||||
@@ -27,6 +27,11 @@ import (
|
|||||||
"golang.org/x/tools/go/ssa"
|
"golang.org/x/tools/go/ssa"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestCollectSkipNames(t *testing.T) {
|
||||||
|
ctx := &context{skips: make(map[string]none)}
|
||||||
|
ctx.collectSkipNames("//llgo:skip abs")
|
||||||
|
}
|
||||||
|
|
||||||
func TestReplaceGoName(t *testing.T) {
|
func TestReplaceGoName(t *testing.T) {
|
||||||
if ret := replaceGoName("foo", 0); ret != "foo" {
|
if ret := replaceGoName("foo", 0); ret != "foo" {
|
||||||
t.Fatal("replaceGoName:", ret)
|
t.Fatal("replaceGoName:", ret)
|
||||||
@@ -155,6 +160,9 @@ func TestPkgKind(t *testing.T) {
|
|||||||
if v, _ := pkgKind("noinit"); v != PkgNoInit {
|
if v, _ := pkgKind("noinit"); v != PkgNoInit {
|
||||||
t.Fatal("pkgKind:", v)
|
t.Fatal("pkgKind:", v)
|
||||||
}
|
}
|
||||||
|
if v, _ := pkgKind("link"); v != PkgLinkIR {
|
||||||
|
t.Fatal("pkgKind:", v)
|
||||||
|
}
|
||||||
if v, _ := pkgKind(""); v != PkgLLGo {
|
if v, _ := pkgKind(""); v != PkgLLGo {
|
||||||
t.Fatal("pkgKind:", v)
|
t.Fatal("pkgKind:", v)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,8 +41,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
cl.SetDebug(cl.DbgFlagAll)
|
|
||||||
llssa.Initialize(llssa.InitAll | llssa.InitNative)
|
llssa.Initialize(llssa.InitAll | llssa.InitNative)
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitDebug() {
|
||||||
|
cl.SetDebug(cl.DbgFlagAll)
|
||||||
llssa.SetDebug(llssa.DbgFlagAll)
|
llssa.SetDebug(llssa.DbgFlagAll)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -136,6 +136,8 @@ type pkgInfo struct {
|
|||||||
kind int
|
kind int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type none struct{}
|
||||||
|
|
||||||
type context struct {
|
type context struct {
|
||||||
prog llssa.Program
|
prog llssa.Program
|
||||||
pkg llssa.Package
|
pkg llssa.Package
|
||||||
@@ -145,7 +147,8 @@ type context struct {
|
|||||||
goTyps *types.Package
|
goTyps *types.Package
|
||||||
goPkg *ssa.Package
|
goPkg *ssa.Package
|
||||||
pyMod string
|
pyMod string
|
||||||
link map[string]string // pkgPath.nameInPkg => linkname
|
link map[string]string // pkgPath.nameInPkg => linkname
|
||||||
|
skips map[string]none
|
||||||
loaded map[*types.Package]*pkgInfo // loaded packages
|
loaded map[*types.Package]*pkgInfo // loaded packages
|
||||||
bvals map[ssa.Value]llssa.Expr // block values
|
bvals map[ssa.Value]llssa.Expr // block values
|
||||||
vargs map[*ssa.Alloc][]llssa.Expr // varargs
|
vargs map[*ssa.Alloc][]llssa.Expr // varargs
|
||||||
@@ -954,19 +957,13 @@ func (p *context) compileValues(b llssa.Builder, vals []ssa.Value, hasVArg int)
|
|||||||
|
|
||||||
// NewPackage compiles a Go package to LLVM IR package.
|
// NewPackage compiles a Go package to LLVM IR package.
|
||||||
func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret llssa.Package, err error) {
|
func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret llssa.Package, err error) {
|
||||||
type namedMember struct {
|
return NewPackageEx(prog, pkg, nil, files)
|
||||||
name string
|
}
|
||||||
val ssa.Member
|
|
||||||
}
|
|
||||||
|
|
||||||
members := make([]*namedMember, 0, len(pkg.Members))
|
|
||||||
for name, v := range pkg.Members {
|
|
||||||
members = append(members, &namedMember{name, v})
|
|
||||||
}
|
|
||||||
sort.Slice(members, func(i, j int) bool {
|
|
||||||
return members[i].name < members[j].name
|
|
||||||
})
|
|
||||||
|
|
||||||
|
// NewPackageEx compiles a Go package (pkg) to LLVM IR package.
|
||||||
|
// The Go package may have an alternative package (alt).
|
||||||
|
// The pkg and alt have the same (Pkg *types.Package).
|
||||||
|
func NewPackageEx(prog llssa.Program, pkg, alt *ssa.Package, files []*ast.File) (ret llssa.Package, err error) {
|
||||||
pkgProg := pkg.Prog
|
pkgProg := pkg.Prog
|
||||||
pkgTypes := pkg.Pkg
|
pkgTypes := pkg.Pkg
|
||||||
pkgName, pkgPath := pkgTypes.Name(), llssa.PathOf(pkgTypes)
|
pkgName, pkgPath := pkgTypes.Name(), llssa.PathOf(pkgTypes)
|
||||||
@@ -983,6 +980,7 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll
|
|||||||
goTyps: pkgTypes,
|
goTyps: pkgTypes,
|
||||||
goPkg: pkg,
|
goPkg: pkg,
|
||||||
link: make(map[string]string),
|
link: make(map[string]string),
|
||||||
|
skips: make(map[string]none),
|
||||||
vargs: make(map[*ssa.Alloc][]llssa.Expr),
|
vargs: make(map[*ssa.Alloc][]llssa.Expr),
|
||||||
loaded: map[*types.Package]*pkgInfo{
|
loaded: map[*types.Package]*pkgInfo{
|
||||||
types.Unsafe: {kind: PkgDeclOnly}, // TODO(xsw): PkgNoInit or PkgDeclOnly?
|
types.Unsafe: {kind: PkgDeclOnly}, // TODO(xsw): PkgNoInit or PkgDeclOnly?
|
||||||
@@ -990,6 +988,38 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll
|
|||||||
}
|
}
|
||||||
ctx.initPyModule()
|
ctx.initPyModule()
|
||||||
ctx.initFiles(pkgPath, files)
|
ctx.initFiles(pkgPath, files)
|
||||||
|
|
||||||
|
if alt != nil {
|
||||||
|
processPkg(ctx, ret, alt)
|
||||||
|
}
|
||||||
|
processPkg(ctx, ret, pkg)
|
||||||
|
for len(ctx.inits) > 0 {
|
||||||
|
inits := ctx.inits
|
||||||
|
ctx.inits = nil
|
||||||
|
for _, ini := range inits {
|
||||||
|
ini()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func processPkg(ctx *context, ret llssa.Package, pkg *ssa.Package) {
|
||||||
|
type namedMember struct {
|
||||||
|
name string
|
||||||
|
val ssa.Member
|
||||||
|
}
|
||||||
|
|
||||||
|
members := make([]*namedMember, 0, len(pkg.Members))
|
||||||
|
skips := ctx.skips
|
||||||
|
for name, v := range pkg.Members {
|
||||||
|
if _, ok := skips[name]; !ok {
|
||||||
|
members = append(members, &namedMember{name, v})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Slice(members, func(i, j int) bool {
|
||||||
|
return members[i].name < members[j].name
|
||||||
|
})
|
||||||
|
|
||||||
for _, m := range members {
|
for _, m := range members {
|
||||||
member := m.val
|
member := m.val
|
||||||
switch member := member.(type) {
|
switch member := member.(type) {
|
||||||
@@ -1006,14 +1036,6 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll
|
|||||||
ctx.compileGlobal(ret, member)
|
ctx.compileGlobal(ret, member)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for len(ctx.inits) > 0 {
|
|
||||||
inits := ctx.inits
|
|
||||||
ctx.inits = nil
|
|
||||||
for _, ini := range inits {
|
|
||||||
ini()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -17,9 +17,14 @@
|
|||||||
package cl_test
|
package cl_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/cl"
|
||||||
"github.com/goplus/llgo/cl/cltest"
|
"github.com/goplus/llgo/cl/cltest"
|
||||||
|
"github.com/goplus/llgo/internal/build"
|
||||||
"github.com/goplus/llgo/ssa"
|
"github.com/goplus/llgo/ssa"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -45,7 +50,9 @@ func TestFromTestlibc(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFromTestrt(t *testing.T) {
|
func TestFromTestrt(t *testing.T) {
|
||||||
|
cl.SetDebug(cl.DbgFlagAll)
|
||||||
cltest.FromDir(t, "", "./_testrt", true)
|
cltest.FromDir(t, "", "./_testrt", true)
|
||||||
|
cl.SetDebug(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFromTestdata(t *testing.T) {
|
func TestFromTestdata(t *testing.T) {
|
||||||
@@ -64,6 +71,15 @@ func TestPython(t *testing.T) {
|
|||||||
cltest.Pkg(t, ssa.PkgPython, "../py/llgo_autogen.ll")
|
cltest.Pkg(t, ssa.PkgPython, "../py/llgo_autogen.ll")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGoLibMath(t *testing.T) {
|
||||||
|
if runtime.GOOS == "darwin" { // TODO(xsw): support linux/windows
|
||||||
|
root, _ := filepath.Abs("..")
|
||||||
|
os.Setenv("LLGOROOT", root)
|
||||||
|
conf := build.NewDefaultConf(build.ModeInstall)
|
||||||
|
build.Do([]string{"math"}, conf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestVar(t *testing.T) {
|
func TestVar(t *testing.T) {
|
||||||
testCompile(t, `package foo
|
testCompile(t, `package foo
|
||||||
|
|
||||||
|
|||||||
57
cl/import.go
57
cl/import.go
@@ -65,15 +65,19 @@ func (p *pkgSymInfo) addSym(fset *token.FileSet, pos token.Pos, fullName, inPkgN
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *pkgSymInfo) initLinknames(ctx *context) {
|
func (p *pkgSymInfo) initLinknames(ctx *context) {
|
||||||
|
sep := []byte{'\n'}
|
||||||
|
commentPrefix := []byte{'/', '/'}
|
||||||
for file, b := range p.files {
|
for file, b := range p.files {
|
||||||
lines := bytes.Split(b, []byte{'\n'})
|
lines := bytes.Split(b, sep)
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
ctx.initLinkname(string(line), func(inPkgName string) (fullName string, isVar, ok bool) {
|
if bytes.HasPrefix(line, commentPrefix) {
|
||||||
if sym, ok := p.syms[inPkgName]; ok && file == sym.file {
|
ctx.initLinkname(string(line), func(inPkgName string) (fullName string, isVar, ok bool) {
|
||||||
return sym.fullName, sym.isVar, true
|
if sym, ok := p.syms[inPkgName]; ok && file == sym.file {
|
||||||
}
|
return sym.fullName, sym.isVar, true
|
||||||
return
|
}
|
||||||
})
|
return
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,10 +172,20 @@ func (p *context) initFiles(pkgPath string, files []*ast.File) {
|
|||||||
fullName, inPkgName := astFuncName(pkgPath, decl)
|
fullName, inPkgName := astFuncName(pkgPath, decl)
|
||||||
p.initLinknameByDoc(decl.Doc, fullName, inPkgName, false)
|
p.initLinknameByDoc(decl.Doc, fullName, inPkgName, false)
|
||||||
case *ast.GenDecl:
|
case *ast.GenDecl:
|
||||||
if decl.Tok == token.VAR && len(decl.Specs) == 1 {
|
switch decl.Tok {
|
||||||
if names := decl.Specs[0].(*ast.ValueSpec).Names; len(names) == 1 {
|
case token.VAR:
|
||||||
inPkgName := names[0].Name
|
if len(decl.Specs) == 1 {
|
||||||
p.initLinknameByDoc(decl.Doc, pkgPath+"."+inPkgName, inPkgName, true)
|
if names := decl.Specs[0].(*ast.ValueSpec).Names; len(names) == 1 {
|
||||||
|
inPkgName := names[0].Name
|
||||||
|
p.initLinknameByDoc(decl.Doc, pkgPath+"."+inPkgName, inPkgName, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case token.IMPORT:
|
||||||
|
if doc := decl.Doc; doc != nil {
|
||||||
|
if n := len(doc.List); n > 0 {
|
||||||
|
line := doc.List[n-1].Text
|
||||||
|
p.collectSkipNames(line)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,6 +193,27 @@ func (p *context) initFiles(pkgPath string, files []*ast.File) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *context) collectSkipNames(line string) {
|
||||||
|
const (
|
||||||
|
skip = "//llgo:skip "
|
||||||
|
skip2 = "// llgo:skip "
|
||||||
|
)
|
||||||
|
if strings.HasPrefix(line, skip2) {
|
||||||
|
p.collectSkip(line, len(skip2))
|
||||||
|
} else if strings.HasPrefix(line, skip) {
|
||||||
|
p.collectSkip(line, len(skip))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) collectSkip(line string, prefix int) {
|
||||||
|
names := strings.Split(line[prefix:], " ")
|
||||||
|
for _, name := range names {
|
||||||
|
if name != "" {
|
||||||
|
p.skips[name] = none{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (p *context) initLinknameByDoc(doc *ast.CommentGroup, fullName, inPkgName string, isVar bool) {
|
func (p *context) initLinknameByDoc(doc *ast.CommentGroup, fullName, inPkgName string, isVar bool) {
|
||||||
if doc != nil {
|
if doc != nil {
|
||||||
if n := len(doc.List); n > 0 {
|
if n := len(doc.List); n > 0 {
|
||||||
|
|||||||
@@ -28,16 +28,18 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"golang.org/x/tools/go/ssa"
|
"golang.org/x/tools/go/ssa"
|
||||||
|
|
||||||
"github.com/goplus/llgo/cl"
|
"github.com/goplus/llgo/cl"
|
||||||
"github.com/goplus/llgo/internal/packages"
|
"github.com/goplus/llgo/internal/packages"
|
||||||
|
"github.com/goplus/llgo/internal/typepatch"
|
||||||
"github.com/goplus/llgo/xtool/clang"
|
"github.com/goplus/llgo/xtool/clang"
|
||||||
clangCheck "github.com/goplus/llgo/xtool/clang/check"
|
|
||||||
"github.com/goplus/llgo/xtool/env"
|
"github.com/goplus/llgo/xtool/env"
|
||||||
|
|
||||||
llssa "github.com/goplus/llgo/ssa"
|
llssa "github.com/goplus/llgo/ssa"
|
||||||
|
clangCheck "github.com/goplus/llgo/xtool/clang/check"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Mode int
|
type Mode int
|
||||||
@@ -94,6 +96,7 @@ func Do(args []string, conf *Config) {
|
|||||||
cfg := &packages.Config{
|
cfg := &packages.Config{
|
||||||
Mode: loadSyntax | packages.NeedDeps | packages.NeedModule | packages.NeedExportFile,
|
Mode: loadSyntax | packages.NeedDeps | packages.NeedModule | packages.NeedExportFile,
|
||||||
BuildFlags: flags,
|
BuildFlags: flags,
|
||||||
|
Fset: token.NewFileSet(),
|
||||||
}
|
}
|
||||||
|
|
||||||
llssa.Initialize(llssa.InitAll)
|
llssa.Initialize(llssa.InitAll)
|
||||||
@@ -145,7 +148,14 @@ func Do(args []string, conf *Config) {
|
|||||||
return rt[1].Types
|
return rt[1].Types
|
||||||
})
|
})
|
||||||
|
|
||||||
pkgs := buildAllPkgs(prog, initial, nil, mode, verbose)
|
imp := func(pkgPath string) *packages.Package {
|
||||||
|
if ret, e := packages.LoadEx(sizes, cfg, pkgPath); e == nil {
|
||||||
|
return ret[0]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgs := buildAllPkgs(prog, imp, initial, nil, mode, verbose)
|
||||||
|
|
||||||
var runtimeFiles []string
|
var runtimeFiles []string
|
||||||
if needRt {
|
if needRt {
|
||||||
@@ -153,7 +163,7 @@ func Do(args []string, conf *Config) {
|
|||||||
for _, v := range pkgs {
|
for _, v := range pkgs {
|
||||||
skip[v.PkgPath] = true
|
skip[v.PkgPath] = true
|
||||||
}
|
}
|
||||||
dpkg := buildAllPkgs(prog, rt[:1], skip, mode, verbose)
|
dpkg := buildAllPkgs(prog, imp, rt[:1], skip, mode, verbose)
|
||||||
for _, pkg := range dpkg {
|
for _, pkg := range dpkg {
|
||||||
if !strings.HasSuffix(pkg.ExportFile, ".ll") {
|
if !strings.HasSuffix(pkg.ExportFile, ".ll") {
|
||||||
continue
|
continue
|
||||||
@@ -192,9 +202,13 @@ func isNeedRuntimeOrPyInit(pkg *packages.Package) (needRuntime, needPyInit bool)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildAllPkgs(prog llssa.Program, initial []*packages.Package, skip map[string]bool, mode Mode, verbose bool) (pkgs []*aPackage) {
|
const (
|
||||||
|
ssaBuildMode = ssa.SanityCheckFunctions
|
||||||
|
)
|
||||||
|
|
||||||
|
func buildAllPkgs(prog llssa.Program, imp importer, initial []*packages.Package, skip map[string]bool, mode Mode, verbose bool) (pkgs []*aPackage) {
|
||||||
// Create SSA-form program representation.
|
// Create SSA-form program representation.
|
||||||
ssaProg, pkgs, errPkgs := allPkgs(initial, ssa.SanityCheckFunctions)
|
ssaProg, pkgs, errPkgs := allPkgs(imp, initial, ssaBuildMode)
|
||||||
ssaProg.Build()
|
ssaProg.Build()
|
||||||
for _, errPkg := range errPkgs {
|
for _, errPkg := range errPkgs {
|
||||||
for _, err := range errPkg.Errors {
|
for _, err := range errPkg.Errors {
|
||||||
@@ -358,7 +372,15 @@ func buildPkg(prog llssa.Program, aPkg *aPackage, mode Mode, verbose bool) {
|
|||||||
pkg.ExportFile = ""
|
pkg.ExportFile = ""
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ret, err := cl.NewPackage(prog, aPkg.SSA, pkg.Syntax)
|
altSSA := aPkg.AltSSA
|
||||||
|
syntax := pkg.Syntax
|
||||||
|
if altPkg := aPkg.AltPkg; altPkg != nil {
|
||||||
|
syntax = append(syntax, altPkg.Syntax...)
|
||||||
|
if altSSA != nil {
|
||||||
|
altSSA.Pkg = typepatch.Pkg(pkg.Types, altPkg.Types)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret, err := cl.NewPackageEx(prog, aPkg.SSA, altSSA, syntax)
|
||||||
check(err)
|
check(err)
|
||||||
if needLLFile(mode) {
|
if needLLFile(mode) {
|
||||||
pkg.ExportFile += ".ll"
|
pkg.ExportFile += ".ll"
|
||||||
@@ -379,11 +401,21 @@ func canSkipToBuild(pkgPath string) bool {
|
|||||||
|
|
||||||
type aPackage struct {
|
type aPackage struct {
|
||||||
*packages.Package
|
*packages.Package
|
||||||
SSA *ssa.Package
|
SSA *ssa.Package
|
||||||
LPkg llssa.Package
|
AltPkg *packages.Package
|
||||||
|
AltSSA *ssa.Package
|
||||||
|
LPkg llssa.Package
|
||||||
}
|
}
|
||||||
|
|
||||||
func allPkgs(initial []*packages.Package, mode ssa.BuilderMode) (prog *ssa.Program, all []*aPackage, errs []*packages.Package) {
|
type none struct{}
|
||||||
|
|
||||||
|
var hasAltPkg = map[string]none{
|
||||||
|
"math": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
type importer = func(pkgPath string) *packages.Package
|
||||||
|
|
||||||
|
func allPkgs(imp importer, initial []*packages.Package, mode ssa.BuilderMode) (prog *ssa.Program, all []*aPackage, errs []*packages.Package) {
|
||||||
var fset *token.FileSet
|
var fset *token.FileSet
|
||||||
if len(initial) > 0 {
|
if len(initial) > 0 {
|
||||||
fset = initial[0].Fset
|
fset = initial[0].Fset
|
||||||
@@ -392,8 +424,18 @@ func allPkgs(initial []*packages.Package, mode ssa.BuilderMode) (prog *ssa.Progr
|
|||||||
prog = ssa.NewProgram(fset, mode)
|
prog = ssa.NewProgram(fset, mode)
|
||||||
packages.Visit(initial, nil, func(p *packages.Package) {
|
packages.Visit(initial, nil, func(p *packages.Package) {
|
||||||
if p.Types != nil && !p.IllTyped {
|
if p.Types != nil && !p.IllTyped {
|
||||||
ssaPkg := prog.CreatePackage(p.Types, p.Syntax, p.TypesInfo, true)
|
var altPkg *packages.Package
|
||||||
all = append(all, &aPackage{p, ssaPkg, nil})
|
var altSSA *ssa.Package
|
||||||
|
var ssaPkg = prog.CreatePackage(p.Types, p.Syntax, p.TypesInfo, true)
|
||||||
|
if imp != nil {
|
||||||
|
if _, ok := hasAltPkg[p.PkgPath]; ok {
|
||||||
|
altPkgPath := "github.com/goplus/llgo/internal/lib/" + p.PkgPath
|
||||||
|
if altPkg = imp(altPkgPath); altPkg != nil { // TODO(xsw): how to minimize import times
|
||||||
|
altSSA = createAltSSAPkg(prog, altPkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
all = append(all, &aPackage{p, ssaPkg, altPkg, altSSA, nil})
|
||||||
} else {
|
} else {
|
||||||
errs = append(errs, p)
|
errs = append(errs, p)
|
||||||
}
|
}
|
||||||
@@ -401,6 +443,37 @@ func allPkgs(initial []*packages.Package, mode ssa.BuilderMode) (prog *ssa.Progr
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ssaProgram struct {
|
||||||
|
Fset *token.FileSet
|
||||||
|
imported map[string]*ssa.Package
|
||||||
|
packages map[*types.Package]*ssa.Package // TODO(xsw): ensure offset of packages
|
||||||
|
}
|
||||||
|
|
||||||
|
func setPkgSSA(prog *ssa.Program, pkg *types.Package, pkgSSA *ssa.Package) {
|
||||||
|
s := (*ssaProgram)(unsafe.Pointer(prog))
|
||||||
|
s.packages[pkg] = pkgSSA
|
||||||
|
}
|
||||||
|
|
||||||
|
func createAltSSAPkg(prog *ssa.Program, alt *packages.Package) *ssa.Package {
|
||||||
|
altPath := alt.Types.Path()
|
||||||
|
altSSA := prog.ImportedPackage(altPath)
|
||||||
|
if altSSA == nil {
|
||||||
|
packages.Visit([]*packages.Package{alt}, nil, func(p *packages.Package) {
|
||||||
|
pkgTypes := p.Types
|
||||||
|
if pkgTypes != nil && !p.IllTyped {
|
||||||
|
pkgSSA := prog.ImportedPackage(pkgTypes.Path())
|
||||||
|
if pkgSSA == nil {
|
||||||
|
prog.CreatePackage(pkgTypes, p.Syntax, p.TypesInfo, true)
|
||||||
|
} else {
|
||||||
|
setPkgSSA(prog, pkgTypes, pkgSSA)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
altSSA = prog.ImportedPackage(altPath)
|
||||||
|
}
|
||||||
|
return altSSA
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// TODO(xsw): complete build flags
|
// TODO(xsw): complete build flags
|
||||||
buildFlags = map[string]bool{
|
buildFlags = map[string]bool{
|
||||||
|
|||||||
@@ -16,12 +16,17 @@
|
|||||||
|
|
||||||
package math
|
package math
|
||||||
|
|
||||||
|
// llgo:skip sin cos
|
||||||
import (
|
import (
|
||||||
_ "unsafe"
|
_ "unsafe"
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/llgo/c"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
LLGoPackage = true
|
||||||
|
)
|
||||||
|
|
||||||
//go:linkname Acos C.acos
|
//go:linkname Acos C.acos
|
||||||
func Acos(x float64) float64
|
func Acos(x float64) float64
|
||||||
|
|
||||||
@@ -169,13 +174,6 @@ func Nextafter(x, y float64) float64
|
|||||||
//go:linkname Pow C.pow
|
//go:linkname Pow C.pow
|
||||||
func Pow(x, y float64) float64
|
func Pow(x, y float64) float64
|
||||||
|
|
||||||
//go:linkname cPow10 C.pow10
|
|
||||||
func cPow10(x c.Int) float64
|
|
||||||
|
|
||||||
func Pow10(x int) float64 {
|
|
||||||
return cPow10(c.Int(x))
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:linkname Remainder C.remainder
|
//go:linkname Remainder C.remainder
|
||||||
func Remainder(x, y float64) float64
|
func Remainder(x, y float64) float64
|
||||||
|
|
||||||
|
|||||||
66
internal/typepatch/patch.go
Normal file
66
internal/typepatch/patch.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* 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 typepatch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type typesScope struct {
|
||||||
|
parent *types.Scope
|
||||||
|
children []*types.Scope
|
||||||
|
number int
|
||||||
|
elems map[string]types.Object // TODO(xsw): ensure offset of elems
|
||||||
|
pos, end token.Pos
|
||||||
|
comment string
|
||||||
|
isFunc bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type object struct {
|
||||||
|
parent *types.Scope
|
||||||
|
pos token.Pos
|
||||||
|
pkg *types.Package // TODO(xsw): ensure offset of pkg
|
||||||
|
unused [8]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type iface struct {
|
||||||
|
tab unsafe.Pointer
|
||||||
|
data unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
func setPkg(o types.Object, pkg *types.Package) {
|
||||||
|
data := (*iface)(unsafe.Pointer(&o)).data
|
||||||
|
(*object)(data).pkg = pkg
|
||||||
|
}
|
||||||
|
|
||||||
|
func setObject(scope *types.Scope, name string, o types.Object) {
|
||||||
|
s := (*typesScope)(unsafe.Pointer(scope))
|
||||||
|
s.elems[name] = o
|
||||||
|
}
|
||||||
|
|
||||||
|
func Pkg(pkg, alt *types.Package) *types.Package {
|
||||||
|
scope := pkg.Scope()
|
||||||
|
altScope := alt.Scope()
|
||||||
|
for _, name := range altScope.Names() {
|
||||||
|
o := altScope.Lookup(name)
|
||||||
|
setPkg(o, pkg)
|
||||||
|
setObject(scope, name, o)
|
||||||
|
}
|
||||||
|
return pkg
|
||||||
|
}
|
||||||
@@ -25,6 +25,10 @@ import (
|
|||||||
"github.com/goplus/llgo/ssa/ssatest"
|
"github.com/goplus/llgo/ssa/ssatest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
ssa.SetDebug(ssa.DbgFlagAll)
|
||||||
|
}
|
||||||
|
|
||||||
func TestFromTestgo(t *testing.T) {
|
func TestFromTestgo(t *testing.T) {
|
||||||
cltest.FromDir(t, "", "../cl/_testgo", false)
|
cltest.FromDir(t, "", "../cl/_testgo", false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,13 +26,6 @@ import (
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
const (
|
|
||||||
ClosureCtx = "__llgo_ctx"
|
|
||||||
ClosureStub = "__llgo_stub."
|
|
||||||
)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
NameValist = "__llgo_va_list"
|
NameValist = "__llgo_va_list"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -564,6 +564,11 @@ func (p Package) cFunc(fullName string, sig *types.Signature) Expr {
|
|||||||
return p.NewFunc(fullName, sig, InC).Expr
|
return p.NewFunc(fullName, sig, InC).Expr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
closureCtx = "__llgo_ctx"
|
||||||
|
closureStub = "__llgo_stub."
|
||||||
|
)
|
||||||
|
|
||||||
func (p Package) closureStub(b Builder, t *types.Struct, v Expr) Expr {
|
func (p Package) closureStub(b Builder, t *types.Struct, v Expr) Expr {
|
||||||
name := v.impl.Name()
|
name := v.impl.Name()
|
||||||
prog := b.Prog
|
prog := b.Prog
|
||||||
@@ -574,9 +579,9 @@ func (p Package) closureStub(b Builder, t *types.Struct, v Expr) Expr {
|
|||||||
sig := v.raw.Type.(*types.Signature)
|
sig := v.raw.Type.(*types.Signature)
|
||||||
n := sig.Params().Len()
|
n := sig.Params().Len()
|
||||||
nret := sig.Results().Len()
|
nret := sig.Results().Len()
|
||||||
ctx := types.NewParam(token.NoPos, nil, ClosureCtx, types.Typ[types.UnsafePointer])
|
ctx := types.NewParam(token.NoPos, nil, closureCtx, types.Typ[types.UnsafePointer])
|
||||||
sig = FuncAddCtx(ctx, sig)
|
sig = FuncAddCtx(ctx, sig)
|
||||||
fn := p.NewFunc(ClosureStub+name, sig, InC)
|
fn := p.NewFunc(closureStub+name, sig, InC)
|
||||||
fn.impl.SetLinkage(llvm.LinkOnceAnyLinkage)
|
fn.impl.SetLinkage(llvm.LinkOnceAnyLinkage)
|
||||||
args := make([]Expr, n)
|
args := make([]Expr, n)
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ func (p goTypes) cvtNamed(t *types.Named) (raw *types.Named, cvt bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p goTypes) cvtClosure(sig *types.Signature) *types.Struct {
|
func (p goTypes) cvtClosure(sig *types.Signature) *types.Struct {
|
||||||
ctx := types.NewParam(token.NoPos, nil, ClosureCtx, types.Typ[types.UnsafePointer])
|
ctx := types.NewParam(token.NoPos, nil, closureCtx, types.Typ[types.UnsafePointer])
|
||||||
raw := p.cvtFunc(sig, ctx)
|
raw := p.cvtFunc(sig, ctx)
|
||||||
flds := []*types.Var{
|
flds := []*types.Var{
|
||||||
types.NewField(token.NoPos, nil, "f", raw, false),
|
types.NewField(token.NoPos, nil, "f", raw, false),
|
||||||
|
|||||||
Reference in New Issue
Block a user