Compare commits
115 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
695d3f3327 | ||
|
|
7979cfcb06 | ||
|
|
2986cb0c5f | ||
|
|
5a175955a9 | ||
|
|
cb507f43a7 | ||
|
|
8b148d72c2 | ||
|
|
616596e571 | ||
|
|
2849fe4841 | ||
|
|
98065e80d0 | ||
|
|
286b520d83 | ||
|
|
769b93a277 | ||
|
|
c30ed1b3c8 | ||
|
|
78d7f984d1 | ||
|
|
e88f7e6659 | ||
|
|
e8ff879943 | ||
|
|
f09d5bd155 | ||
|
|
53e73fc622 | ||
|
|
ba94d6f04e | ||
|
|
449f91ab14 | ||
|
|
70623dd554 | ||
|
|
35dc6dcd85 | ||
|
|
41dfafe957 | ||
|
|
2cc1bdee19 | ||
|
|
eb4146d80d | ||
|
|
0d68066086 | ||
|
|
7039cb3bc2 | ||
|
|
510f2f4769 | ||
|
|
5415f68c1b | ||
|
|
475f0fa2ff | ||
|
|
c58b1140d8 | ||
|
|
c97c1e97b9 | ||
|
|
ba3d82e5e5 | ||
|
|
d432899b42 | ||
|
|
08da38a609 | ||
|
|
6a3eb2f2f9 | ||
|
|
6a02c3ac4c | ||
|
|
f1761c0c9c | ||
|
|
39076c75cf | ||
|
|
3be8cacc24 | ||
|
|
46a9df47e4 | ||
|
|
d44a31cc62 | ||
|
|
00b2fd1479 | ||
|
|
5f08e7a612 | ||
|
|
5c8725373a | ||
|
|
c455f6e730 | ||
|
|
3cc83b8ec4 | ||
|
|
f74de76d70 | ||
|
|
ea8ddc6451 | ||
|
|
5f36c37cf2 | ||
|
|
2ad2873278 | ||
|
|
3855895808 | ||
|
|
f86cd74a98 | ||
|
|
1e6ecbadcd | ||
|
|
33716a3385 | ||
|
|
252f0bf967 | ||
|
|
2c3e1d1055 | ||
|
|
aafa639bf1 | ||
|
|
815a8a74fc | ||
|
|
840ea80e20 | ||
|
|
773ae2c8c6 | ||
|
|
4aadb4b86f | ||
|
|
91d1d71f6d | ||
|
|
a3d6a94600 | ||
|
|
43ae7a23b2 | ||
|
|
b6005886fa | ||
|
|
28dd34a136 | ||
|
|
3a3c263203 | ||
|
|
87b7ecd1d6 | ||
|
|
f5a309b5ad | ||
|
|
0f00add402 | ||
|
|
1014fa53dd | ||
|
|
04568835bd | ||
|
|
e4f8edc07c | ||
|
|
a8533d1677 | ||
|
|
edcb66afb7 | ||
|
|
bc1821e7a5 | ||
|
|
3f49fe9e98 | ||
|
|
6aee76be72 | ||
|
|
a2c6e5d7fc | ||
|
|
cbaf9e21b2 | ||
|
|
81b3add443 | ||
|
|
c3e681a7b3 | ||
|
|
1567989142 | ||
|
|
5b73480540 | ||
|
|
b1342d8d97 | ||
|
|
2cbcc53c54 | ||
|
|
b4da61df86 | ||
|
|
edb7a4e1a5 | ||
|
|
0387a35112 | ||
|
|
aafe5a8600 | ||
|
|
67af68ae10 | ||
|
|
bc472a4fac | ||
|
|
2d8f5dbc51 | ||
|
|
9b7d5e2c57 | ||
|
|
f1e676a14f | ||
|
|
34d83813ec | ||
|
|
92b7d61b55 | ||
|
|
5d48e42069 | ||
|
|
ead09d94aa | ||
|
|
7240da07b4 | ||
|
|
72084b5648 | ||
|
|
2d75c55d36 | ||
|
|
da71e7c01b | ||
|
|
5343a55395 | ||
|
|
bbfe2a051c | ||
|
|
c1b0751ea5 | ||
|
|
2ee1f3373b | ||
|
|
088995088c | ||
|
|
b9ab96c89b | ||
|
|
576c276f33 | ||
|
|
0a879cb0be | ||
|
|
177ba6de48 | ||
|
|
4d1079261b | ||
|
|
f6ab8834fa | ||
|
|
2142e14b6d |
19
.github/dependabot.yml
vendored
Normal file
19
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# To get started with Dependabot version updates, you'll need to specify which
|
||||||
|
# package ecosystems to update and where the package manifests are located.
|
||||||
|
# Please see the documentation for all configuration options:
|
||||||
|
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: github-actions
|
||||||
|
directory: /
|
||||||
|
labels:
|
||||||
|
- dependabot
|
||||||
|
- actions
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
|
||||||
|
- package-ecosystem: "gomod" # See documentation for possible values
|
||||||
|
directory: "/" # Location of package manifests
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
16
.github/workflows/go.yml
vendored
16
.github/workflows/go.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
llvm: [17]
|
llvm: [17]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Update Homebrew
|
- name: Update Homebrew
|
||||||
if: matrix.llvm == 17 # needed as long as LLVM 17 is still fresh
|
if: matrix.llvm == 17 # needed as long as LLVM 17 is still fresh
|
||||||
@@ -26,7 +26,7 @@ jobs:
|
|||||||
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@${{ matrix.llvm }}
|
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@${{ matrix.llvm }}
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.20'
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
llvm: [17]
|
llvm: [17]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install LLVM ${{ matrix.llvm }}
|
- name: Install LLVM ${{ matrix.llvm }}
|
||||||
run: |
|
run: |
|
||||||
@@ -52,7 +52,7 @@ jobs:
|
|||||||
sudo apt-get install --no-install-recommends llvm-${{ matrix.llvm }}-dev
|
sudo apt-get install --no-install-recommends llvm-${{ matrix.llvm }}-dev
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.20'
|
||||||
|
|
||||||
@@ -60,4 +60,10 @@ jobs:
|
|||||||
run: go build -v ./...
|
run: go build -v ./...
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: go test -v ./...
|
run: go test -v -coverprofile="coverage.txt" -covermode=atomic ./...
|
||||||
|
|
||||||
|
- name: Upload coverage reports to Codecov
|
||||||
|
uses: codecov/codecov-action@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
slug: goplus/llgo
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -8,6 +8,10 @@
|
|||||||
*.so
|
*.so
|
||||||
*.dylib
|
*.dylib
|
||||||
|
|
||||||
|
err.log
|
||||||
|
|
||||||
|
_go/
|
||||||
|
_runtime/
|
||||||
_tinygo/
|
_tinygo/
|
||||||
|
|
||||||
# Test binary, built with `go test -c`
|
# Test binary, built with `go test -c`
|
||||||
|
|||||||
@@ -3,8 +3,9 @@ llgo - A Go compiler based on LLVM
|
|||||||
|
|
||||||
[](https://github.com/goplus/llgo/actions/workflows/go.yml)
|
[](https://github.com/goplus/llgo/actions/workflows/go.yml)
|
||||||
[](https://goreportcard.com/report/github.com/goplus/llgo)
|
[](https://goreportcard.com/report/github.com/goplus/llgo)
|
||||||
[](https://pkg.go.dev/github.com/goplus/llgo)
|
|
||||||
<!--
|
|
||||||
[](https://github.com/goplus/llgo/releases)
|
[](https://github.com/goplus/llgo/releases)
|
||||||
[](https://codecov.io/gh/goplus/llgo)
|
[](https://codecov.io/gh/goplus/llgo)
|
||||||
-->
|
[](https://pkg.go.dev/github.com/goplus/llgo)
|
||||||
|
[](https://github.com/goplus/gop)
|
||||||
|
|
||||||
|
This is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem. It's a subproject of [the Go+ project](https://github.com/goplus/gop).
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2023 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 build
|
|
||||||
|
|
||||||
import (
|
|
||||||
"go/build"
|
|
||||||
)
|
|
||||||
|
|
||||||
// An ImportMode controls the behavior of the Import method.
|
|
||||||
type ImportMode = build.ImportMode
|
|
||||||
|
|
||||||
// A Package describes the Go package found in a directory.
|
|
||||||
type Package struct {
|
|
||||||
*build.Package
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Context specifies the supporting context for a build.
|
|
||||||
type Context struct {
|
|
||||||
*build.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
// Import returns details about the Go package named by the import path,
|
|
||||||
// interpreting local import paths relative to the srcDir directory.
|
|
||||||
// If the path is a local import path naming a package that can be imported
|
|
||||||
// using a standard import path, the returned package will set p.ImportPath
|
|
||||||
// to that path.
|
|
||||||
//
|
|
||||||
// If an error occurs, Import returns a non-nil error and a non-nil
|
|
||||||
// *Package containing partial information.
|
|
||||||
func (ctxt Context) Import(path string, srcDir string, mode ImportMode) (ret Package, err error) {
|
|
||||||
pkg, err := build.Import(path, srcDir, mode)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ret = Package{pkg}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImportDir is like Import but processes the Go package found in
|
|
||||||
// the named directory.
|
|
||||||
func (ctxt *Context) ImportDir(dir string, mode ImportMode) (Package, error) {
|
|
||||||
return ctxt.Import(".", dir, mode)
|
|
||||||
}
|
|
||||||
@@ -20,21 +20,35 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/goplus/llgo/x/llgen"
|
"github.com/goplus/llgo/internal/llgen"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) != 2 {
|
if len(os.Args) < 2 {
|
||||||
fmt.Fprintln(os.Stderr, "Usage: llgen xxx.go")
|
fmt.Fprintln(os.Stderr, "Usage: llgen <pkg> [pkgPath]")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
inFile := os.Args[1]
|
inFile := os.Args[1]
|
||||||
|
|
||||||
dir, _ := filepath.Split(inFile)
|
dir, _ := filepath.Split(inFile)
|
||||||
outFile := dir + "out.ll"
|
fname := "llgo_autogen.ll"
|
||||||
|
if inCompilerDir(dir) {
|
||||||
|
fname = "out.ll"
|
||||||
|
}
|
||||||
|
outFile := dir + fname
|
||||||
|
|
||||||
llgen.Init()
|
llgen.Init()
|
||||||
llgen.Do(inFile, outFile)
|
if len(os.Args) >= 3 {
|
||||||
|
llgen.Do(os.Args[2], inFile, outFile)
|
||||||
|
} else {
|
||||||
|
llgen.DoFile(inFile, outFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func inCompilerDir(dir string) bool {
|
||||||
|
dir, _ = filepath.Abs(dir)
|
||||||
|
return strings.Contains(filepath.ToSlash(dir), "/llgo/cl/")
|
||||||
}
|
}
|
||||||
|
|||||||
201
chore/ssadump/ssadump.go
Normal file
201
chore/ssadump/ssadump.go
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// ssadump: a tool for displaying and interpreting the SSA form of Go programs.
|
||||||
|
package main // import "golang.org/x/tools/cmd/ssadump"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"go/build"
|
||||||
|
"go/types"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"runtime/pprof"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/buildutil"
|
||||||
|
"golang.org/x/tools/go/packages"
|
||||||
|
"golang.org/x/tools/go/ssa"
|
||||||
|
"golang.org/x/tools/go/ssa/interp"
|
||||||
|
"golang.org/x/tools/go/ssa/ssautil"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
loadFiles = packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles
|
||||||
|
loadImports = loadFiles | packages.NeedImports
|
||||||
|
loadTypes = loadImports | packages.NeedTypes | packages.NeedTypesSizes
|
||||||
|
loadSyntax = loadTypes | packages.NeedSyntax | packages.NeedTypesInfo
|
||||||
|
)
|
||||||
|
|
||||||
|
// flags
|
||||||
|
var (
|
||||||
|
mode = ssa.BuilderMode(0)
|
||||||
|
|
||||||
|
testFlag = flag.Bool("test", false, "include implicit test packages and executables")
|
||||||
|
|
||||||
|
runFlag = flag.Bool("run", false, "interpret the SSA program")
|
||||||
|
|
||||||
|
interpFlag = flag.String("interp", "", `Options controlling the SSA test interpreter.
|
||||||
|
The value is a sequence of zero or more more of these letters:
|
||||||
|
R disable [R]ecover() from panic; show interpreter crash instead.
|
||||||
|
T [T]race execution of the program. Best for single-threaded programs!
|
||||||
|
`)
|
||||||
|
|
||||||
|
cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
|
||||||
|
|
||||||
|
args stringListValue
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
flag.Var(&mode, "build", ssa.BuilderModeDoc)
|
||||||
|
flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)
|
||||||
|
flag.Var(&args, "arg", "add argument to interpreted program")
|
||||||
|
}
|
||||||
|
|
||||||
|
const usage = `SSA builder and interpreter.
|
||||||
|
Usage: ssadump [-build=[DBCSNFLG]] [-test] [-run] [-interp=[TR]] [-arg=...] package...
|
||||||
|
Use -help flag to display options.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
% ssadump -build=F hello.go # dump SSA form of a single package
|
||||||
|
% ssadump -build=F -test fmt # dump SSA form of a package and its tests
|
||||||
|
% ssadump -run -interp=T hello.go # interpret a program, with tracing
|
||||||
|
|
||||||
|
The -run flag causes ssadump to build the code in a runnable form and run the first
|
||||||
|
package named main.
|
||||||
|
|
||||||
|
Interpretation of the standard "testing" package is no longer supported.
|
||||||
|
`
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := doMain(); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "ssadump: %s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func doMain() error {
|
||||||
|
flag.Parse()
|
||||||
|
if len(flag.Args()) == 0 {
|
||||||
|
fmt.Fprint(os.Stderr, usage)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := &packages.Config{
|
||||||
|
Mode: loadSyntax,
|
||||||
|
Tests: *testFlag,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Choose types.Sizes from conf.Build.
|
||||||
|
// TODO(adonovan): remove this when go/packages provides a better way.
|
||||||
|
var wordSize int64 = 8
|
||||||
|
switch build.Default.GOARCH {
|
||||||
|
case "386", "arm":
|
||||||
|
wordSize = 4
|
||||||
|
}
|
||||||
|
sizes := &types.StdSizes{
|
||||||
|
MaxAlign: 8,
|
||||||
|
WordSize: wordSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
var interpMode interp.Mode
|
||||||
|
for _, c := range *interpFlag {
|
||||||
|
switch c {
|
||||||
|
case 'T':
|
||||||
|
interpMode |= interp.EnableTracing
|
||||||
|
case 'R':
|
||||||
|
interpMode |= interp.DisableRecover
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown -interp option: '%c'", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Profiling support.
|
||||||
|
if *cpuprofile != "" {
|
||||||
|
f, err := os.Create(*cpuprofile)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
pprof.StartCPUProfile(f)
|
||||||
|
defer pprof.StopCPUProfile()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load, parse and type-check the initial packages,
|
||||||
|
// and, if -run, their dependencies.
|
||||||
|
if *runFlag {
|
||||||
|
cfg.Mode = loadSyntax | packages.NeedDeps
|
||||||
|
}
|
||||||
|
initial, err := packages.Load(cfg, flag.Args()...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(initial) == 0 {
|
||||||
|
return fmt.Errorf("no packages")
|
||||||
|
}
|
||||||
|
if packages.PrintErrors(initial) > 0 {
|
||||||
|
return fmt.Errorf("packages contain errors")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn on instantiating generics during build if the program will be run.
|
||||||
|
if *runFlag {
|
||||||
|
mode |= ssa.InstantiateGenerics
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create SSA-form program representation.
|
||||||
|
prog, pkgs := ssautil.AllPackages(initial, mode)
|
||||||
|
|
||||||
|
for i, p := range pkgs {
|
||||||
|
if p == nil {
|
||||||
|
return fmt.Errorf("cannot build SSA for package %s", initial[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !*runFlag {
|
||||||
|
// Build and display only the initial packages
|
||||||
|
// (and synthetic wrappers).
|
||||||
|
for _, p := range pkgs {
|
||||||
|
p.Build()
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Run the interpreter.
|
||||||
|
// Build SSA for all packages.
|
||||||
|
prog.Build()
|
||||||
|
|
||||||
|
// Earlier versions of the interpreter needed the runtime
|
||||||
|
// package; however, interp cannot handle unsafe constructs
|
||||||
|
// used during runtime's package initialization at the moment.
|
||||||
|
// The key construct blocking support is:
|
||||||
|
// *((*T)(unsafe.Pointer(p)))
|
||||||
|
// Unfortunately, this means only trivial programs can be
|
||||||
|
// interpreted by ssadump.
|
||||||
|
if prog.ImportedPackage("runtime") != nil {
|
||||||
|
return fmt.Errorf("-run: program depends on runtime package (interpreter can run only trivial programs)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if runtime.GOARCH != build.Default.GOARCH {
|
||||||
|
return fmt.Errorf("cross-interpretation is not supported (target has GOARCH %s, interpreter has %s)",
|
||||||
|
build.Default.GOARCH, runtime.GOARCH)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run first main package.
|
||||||
|
for _, main := range ssautil.MainPackages(pkgs) {
|
||||||
|
fmt.Fprintf(os.Stderr, "Running: %s\n", main.Pkg.Path())
|
||||||
|
os.Exit(interp.Interpret(main, interpMode, sizes, main.Pkg.Path(), args))
|
||||||
|
}
|
||||||
|
return fmt.Errorf("no main package")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// stringListValue is a flag.Value that accumulates strings.
|
||||||
|
// e.g. --flag=one --flag=two would produce []string{"one", "two"}.
|
||||||
|
type stringListValue []string
|
||||||
|
|
||||||
|
func (ss *stringListValue) Get() interface{} { return []string(*ss) }
|
||||||
|
|
||||||
|
func (ss *stringListValue) String() string { return fmt.Sprintf("%q", *ss) }
|
||||||
|
|
||||||
|
func (ss *stringListValue) Set(s string) error { *ss = append(*ss, s); return nil }
|
||||||
16
cl/_testcgo/any/in.go
Normal file
16
cl/_testcgo/any/in.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import _ "unsafe"
|
||||||
|
|
||||||
|
func incVal(a any) int {
|
||||||
|
return a.(int) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname printf C.printf
|
||||||
|
func printf(format *int8, __llgo_va_list ...any)
|
||||||
|
|
||||||
|
var format = [...]int8{'H', 'e', 'l', 'l', 'o', ' ', '%', 'd', '\n', 0}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
printf(&format[0], incVal(100))
|
||||||
|
}
|
||||||
55
cl/_testcgo/any/out.ll
Normal file
55
cl/_testcgo/any/out.ll
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
; ModuleID = 'main'
|
||||||
|
source_filename = "main"
|
||||||
|
|
||||||
|
%"github.com/goplus/llgo/internal/runtime.iface" = type { ptr, ptr }
|
||||||
|
|
||||||
|
@main.format = global ptr null
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
|
||||||
|
define i64 @main.incVal(%"github.com/goplus/llgo/internal/runtime.iface" %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 2)
|
||||||
|
%2 = call i64 @"github.com/goplus/llgo/internal/runtime.I2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %1)
|
||||||
|
%3 = add i64 %2, 1
|
||||||
|
ret i64 %3
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
store i8 72, ptr @main.format, align 1
|
||||||
|
store i8 101, ptr getelementptr inbounds (i8, ptr @main.format, i64 1), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 2), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 3), align 1
|
||||||
|
store i8 111, ptr getelementptr inbounds (i8, ptr @main.format, i64 4), align 1
|
||||||
|
store i8 32, ptr getelementptr inbounds (i8, ptr @main.format, i64 5), align 1
|
||||||
|
store i8 37, ptr getelementptr inbounds (i8, ptr @main.format, i64 6), align 1
|
||||||
|
store i8 100, ptr getelementptr inbounds (i8, ptr @main.format, i64 7), align 1
|
||||||
|
store i8 10, ptr getelementptr inbounds (i8, ptr @main.format, i64 8), align 1
|
||||||
|
store i8 0, ptr getelementptr inbounds (i8, ptr @main.format, i64 9), align 1
|
||||||
|
br label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @main() {
|
||||||
|
_llgo_0:
|
||||||
|
call void @main.init()
|
||||||
|
%0 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(i64 100)
|
||||||
|
%1 = call i64 @main.incVal(%"github.com/goplus/llgo/internal/runtime.iface" %0)
|
||||||
|
call void (ptr, ...) @printf(ptr @main.format, i64 %1)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @printf(ptr, ...)
|
||||||
|
|
||||||
|
declare i64 @"github.com/goplus/llgo/internal/runtime.I2Int"(%"github.com/goplus/llgo/internal/runtime.iface", ptr)
|
||||||
|
|
||||||
|
declare ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64)
|
||||||
|
|
||||||
|
declare %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr, i64)
|
||||||
10
cl/_testcgo/hello/in.go
Normal file
10
cl/_testcgo/hello/in.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/goplus/llgo/cl/internal/libc"
|
||||||
|
|
||||||
|
var format = [...]int8{'H', 'e', 'l', 'l', 'o', ' ', '%', 'd', '\n', 0}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
sfmt := &format[0]
|
||||||
|
libc.Printf(sfmt, libc.Strlen(sfmt))
|
||||||
|
}
|
||||||
43
cl/_testcgo/hello/out.ll
Normal file
43
cl/_testcgo/hello/out.ll
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
; ModuleID = 'main'
|
||||||
|
source_filename = "main"
|
||||||
|
|
||||||
|
@main.format = global ptr null
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
|
||||||
|
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 @"github.com/goplus/llgo/cl/internal/libc.init"()
|
||||||
|
store i8 72, ptr @main.format, align 1
|
||||||
|
store i8 101, ptr getelementptr inbounds (i8, ptr @main.format, i64 1), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 2), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 3), align 1
|
||||||
|
store i8 111, ptr getelementptr inbounds (i8, ptr @main.format, i64 4), align 1
|
||||||
|
store i8 32, ptr getelementptr inbounds (i8, ptr @main.format, i64 5), align 1
|
||||||
|
store i8 37, ptr getelementptr inbounds (i8, ptr @main.format, i64 6), align 1
|
||||||
|
store i8 100, ptr getelementptr inbounds (i8, ptr @main.format, i64 7), align 1
|
||||||
|
store i8 10, ptr getelementptr inbounds (i8, ptr @main.format, i64 8), align 1
|
||||||
|
store i8 0, ptr getelementptr inbounds (i8, ptr @main.format, i64 9), align 1
|
||||||
|
br label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @main() {
|
||||||
|
_llgo_0:
|
||||||
|
call void @main.init()
|
||||||
|
%0 = call i32 @strlen(ptr @main.format)
|
||||||
|
call void (ptr, ...) @"github.com/goplus/llgo/cl/internal/libc.Printf"(ptr @main.format, i32 %0)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/cl/internal/libc.init"()
|
||||||
|
|
||||||
|
declare i32 @strlen(ptr)
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/cl/internal/libc.Printf"(ptr, ...)
|
||||||
17
cl/_testcgo/strlen/in.go
Normal file
17
cl/_testcgo/strlen/in.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "C"
|
||||||
|
import _ "unsafe"
|
||||||
|
|
||||||
|
//go:linkname printf C.printf
|
||||||
|
func printf(format *int8, __llgo_va_list ...any)
|
||||||
|
|
||||||
|
//go:linkname strlen C.strlen
|
||||||
|
func strlen(str *int8) C.int
|
||||||
|
|
||||||
|
var format = [...]int8{'H', 'e', 'l', 'l', 'o', ' ', '%', 'd', '\n', 0}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
sfmt := &format[0]
|
||||||
|
printf(sfmt, strlen(sfmt))
|
||||||
|
}
|
||||||
40
cl/_testcgo/strlen/out.ll
Normal file
40
cl/_testcgo/strlen/out.ll
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
; ModuleID = 'main'
|
||||||
|
source_filename = "main"
|
||||||
|
|
||||||
|
@main.format = global ptr null
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
|
||||||
|
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
|
||||||
|
store i8 72, ptr @main.format, align 1
|
||||||
|
store i8 101, ptr getelementptr inbounds (i8, ptr @main.format, i64 1), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 2), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 3), align 1
|
||||||
|
store i8 111, ptr getelementptr inbounds (i8, ptr @main.format, i64 4), align 1
|
||||||
|
store i8 32, ptr getelementptr inbounds (i8, ptr @main.format, i64 5), align 1
|
||||||
|
store i8 37, ptr getelementptr inbounds (i8, ptr @main.format, i64 6), align 1
|
||||||
|
store i8 100, ptr getelementptr inbounds (i8, ptr @main.format, i64 7), align 1
|
||||||
|
store i8 10, ptr getelementptr inbounds (i8, ptr @main.format, i64 8), align 1
|
||||||
|
store i8 0, ptr getelementptr inbounds (i8, ptr @main.format, i64 9), align 1
|
||||||
|
br label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @main() {
|
||||||
|
_llgo_0:
|
||||||
|
call void @main.init()
|
||||||
|
%0 = call i32 @strlen(ptr @main.format)
|
||||||
|
call void (ptr, ...) @printf(ptr @main.format, i32 %0)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @printf(ptr, ...)
|
||||||
|
|
||||||
|
declare i32 @strlen(ptr)
|
||||||
25
cl/_testcgo/struct/in.go
Normal file
25
cl/_testcgo/struct/in.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "C"
|
||||||
|
import _ "unsafe"
|
||||||
|
|
||||||
|
//go:linkname printf C.printf
|
||||||
|
func printf(format *int8, __llgo_va_list ...any)
|
||||||
|
|
||||||
|
type Foo struct {
|
||||||
|
A C.int
|
||||||
|
ok bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var format = [...]int8{'H', 'e', 'l', 'l', 'o', ' ', '%', 'd', '\n', 0}
|
||||||
|
|
||||||
|
func (p Foo) Print() {
|
||||||
|
if p.ok {
|
||||||
|
printf(&format[0], p.A)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
foo := Foo{100, true}
|
||||||
|
foo.Print()
|
||||||
|
}
|
||||||
70
cl/_testcgo/struct/out.ll
Normal file
70
cl/_testcgo/struct/out.ll
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
; ModuleID = 'main'
|
||||||
|
source_filename = "main"
|
||||||
|
|
||||||
|
%main.Foo = type { i32, i1 }
|
||||||
|
|
||||||
|
@main.format = global ptr null
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
|
||||||
|
define void @"(main.Foo).Print"(%main.Foo %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = alloca %main.Foo, align 8
|
||||||
|
store %main.Foo %0, ptr %1, align 4
|
||||||
|
%2 = getelementptr inbounds %main.Foo, ptr %1, i32 0, i32 1
|
||||||
|
%3 = load i1, ptr %2, align 1
|
||||||
|
br i1 %3, label %_llgo_1, label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
%4 = getelementptr inbounds %main.Foo, ptr %1, i32 0, i32 0
|
||||||
|
%5 = load i32, ptr %4, align 4
|
||||||
|
call void (ptr, ...) @printf(ptr @main.format, i32 %5)
|
||||||
|
br label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @"(*main.Foo).Print"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = load %main.Foo, ptr %0, align 4
|
||||||
|
call void @"(main.Foo).Print"(%main.Foo %1)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
store i8 72, ptr @main.format, align 1
|
||||||
|
store i8 101, ptr getelementptr inbounds (i8, ptr @main.format, i64 1), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 2), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 3), align 1
|
||||||
|
store i8 111, ptr getelementptr inbounds (i8, ptr @main.format, i64 4), align 1
|
||||||
|
store i8 32, ptr getelementptr inbounds (i8, ptr @main.format, i64 5), align 1
|
||||||
|
store i8 37, ptr getelementptr inbounds (i8, ptr @main.format, i64 6), align 1
|
||||||
|
store i8 100, ptr getelementptr inbounds (i8, ptr @main.format, i64 7), align 1
|
||||||
|
store i8 10, ptr getelementptr inbounds (i8, ptr @main.format, i64 8), align 1
|
||||||
|
store i8 0, ptr getelementptr inbounds (i8, ptr @main.format, i64 9), align 1
|
||||||
|
br label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @main() {
|
||||||
|
_llgo_0:
|
||||||
|
call void @main.init()
|
||||||
|
%0 = alloca %main.Foo, align 8
|
||||||
|
%1 = getelementptr inbounds %main.Foo, ptr %0, i32 0, i32 0
|
||||||
|
%2 = getelementptr inbounds %main.Foo, ptr %0, i32 0, i32 1
|
||||||
|
store i32 100, ptr %1, align 4
|
||||||
|
store i1 true, ptr %2, align 1
|
||||||
|
%3 = load %main.Foo, ptr %0, align 4
|
||||||
|
call void @"(main.Foo).Print"(%main.Foo %3)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @printf(ptr, ...)
|
||||||
25
cl/_testcgo/typalias/in.go
Normal file
25
cl/_testcgo/typalias/in.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "C"
|
||||||
|
import _ "unsafe"
|
||||||
|
|
||||||
|
//go:linkname printf C.printf
|
||||||
|
func printf(format *int8, __llgo_va_list ...any)
|
||||||
|
|
||||||
|
type Foo = struct {
|
||||||
|
A C.int
|
||||||
|
ok bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var format = [...]int8{'H', 'e', 'l', 'l', 'o', ' ', '%', 'd', '\n', 0}
|
||||||
|
|
||||||
|
func Print(p *Foo) {
|
||||||
|
if p.ok {
|
||||||
|
printf(&format[0], p.A)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
foo := &Foo{100, true}
|
||||||
|
Print(foo)
|
||||||
|
}
|
||||||
60
cl/_testcgo/typalias/out.ll
Normal file
60
cl/_testcgo/typalias/out.ll
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
; ModuleID = 'main'
|
||||||
|
source_filename = "main"
|
||||||
|
|
||||||
|
@main.format = global ptr null
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
|
||||||
|
define void @main.Print(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds { i32, i1 }, ptr %0, i32 0, i32 1
|
||||||
|
%2 = load i1, ptr %1, align 1
|
||||||
|
br i1 %2, label %_llgo_1, label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
%3 = getelementptr inbounds { i32, i1 }, ptr %0, i32 0, i32 0
|
||||||
|
%4 = load i32, ptr %3, align 4
|
||||||
|
call void (ptr, ...) @printf(ptr @main.format, i32 %4)
|
||||||
|
br label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
store i8 72, ptr @main.format, align 1
|
||||||
|
store i8 101, ptr getelementptr inbounds (i8, ptr @main.format, i64 1), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 2), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 3), align 1
|
||||||
|
store i8 111, ptr getelementptr inbounds (i8, ptr @main.format, i64 4), align 1
|
||||||
|
store i8 32, ptr getelementptr inbounds (i8, ptr @main.format, i64 5), align 1
|
||||||
|
store i8 37, ptr getelementptr inbounds (i8, ptr @main.format, i64 6), align 1
|
||||||
|
store i8 100, ptr getelementptr inbounds (i8, ptr @main.format, i64 7), align 1
|
||||||
|
store i8 10, ptr getelementptr inbounds (i8, ptr @main.format, i64 8), align 1
|
||||||
|
store i8 0, ptr getelementptr inbounds (i8, ptr @main.format, i64 9), align 1
|
||||||
|
br label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @main() {
|
||||||
|
_llgo_0:
|
||||||
|
call void @main.init()
|
||||||
|
%0 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16)
|
||||||
|
%1 = getelementptr inbounds { i32, i1 }, ptr %0, i32 0, i32 0
|
||||||
|
%2 = getelementptr inbounds { i32, i1 }, ptr %0, i32 0, i32 1
|
||||||
|
store i32 100, ptr %1, align 4
|
||||||
|
store i1 true, ptr %2, align 1
|
||||||
|
call void @main.Print(ptr %0)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @printf(ptr, ...)
|
||||||
|
|
||||||
|
declare ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64)
|
||||||
8
cl/_testdata/apkg/in.go
Normal file
8
cl/_testdata/apkg/in.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package apkg
|
||||||
|
|
||||||
|
func Max(a, b float64) float64 {
|
||||||
|
if a > b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
29
cl/_testdata/apkg/out.ll
Normal file
29
cl/_testdata/apkg/out.ll
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
; ModuleID = 'apkg'
|
||||||
|
source_filename = "apkg"
|
||||||
|
|
||||||
|
@"apkg.init$guard" = global ptr null
|
||||||
|
|
||||||
|
define double @apkg.Max(double %0, double %1) {
|
||||||
|
_llgo_0:
|
||||||
|
%2 = fcmp ogt double %0, %1
|
||||||
|
br i1 %2, label %_llgo_1, label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
ret double %0
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_0
|
||||||
|
ret double %1
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @apkg.init() {
|
||||||
|
_llgo_0:
|
||||||
|
%0 = load i1, ptr @"apkg.init$guard", align 1
|
||||||
|
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
store i1 true, ptr @"apkg.init$guard", align 1
|
||||||
|
br label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
@@ -1,22 +1,29 @@
|
|||||||
; ModuleID = 'main'
|
; ModuleID = 'main'
|
||||||
source_filename = "main"
|
source_filename = "main"
|
||||||
|
|
||||||
@"init$guard" = global ptr null
|
@"main.init$guard" = global ptr null
|
||||||
|
|
||||||
define void @init() {
|
define void @main.init() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
%0 = load i1, ptr @"init$guard", align 1
|
%0 = load i1, ptr @"main.init$guard", align 1
|
||||||
br i1 %0, label %_llgo_2, label %_llgo_1
|
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||||
|
|
||||||
_llgo_1: ; preds = %_llgo_0
|
_llgo_1: ; preds = %_llgo_0
|
||||||
store i1 true, ptr @"init$guard", align 1
|
store i1 true, ptr @"main.init$guard", align 1
|
||||||
br label %_llgo_2
|
br label %_llgo_2
|
||||||
|
|
||||||
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
define i64 @max(i64 %0, i64 %1) {
|
define void @main() {
|
||||||
|
_llgo_0:
|
||||||
|
call void @main.init()
|
||||||
|
%0 = call i64 @main.max(i64 1, i64 2)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @main.max(i64 %0, i64 %1) {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
%2 = icmp sgt i64 %0, %1
|
%2 = icmp sgt i64 %0, %1
|
||||||
br i1 %2, label %_llgo_1, label %_llgo_2
|
br i1 %2, label %_llgo_1, label %_llgo_2
|
||||||
@@ -27,10 +34,3 @@ _llgo_1: ; preds = %_llgo_0
|
|||||||
_llgo_2: ; preds = %_llgo_0
|
_llgo_2: ; preds = %_llgo_0
|
||||||
ret i64 %1
|
ret i64 %1
|
||||||
}
|
}
|
||||||
|
|
||||||
define void @main() {
|
|
||||||
_llgo_0:
|
|
||||||
call void @init()
|
|
||||||
%0 = call i64 @max(i64 1, i64 2)
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
|||||||
10
cl/_testdata/importpkg/in.go
Normal file
10
cl/_testdata/importpkg/in.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/goplus/llgo/cl/internal/stdio"
|
||||||
|
|
||||||
|
var hello = [...]int8{'H', 'e', 'l', 'l', 'o', '\n', 0}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
_ = stdio.Max(2, 100)
|
||||||
|
stdio.Printf(&hello[0])
|
||||||
|
}
|
||||||
40
cl/_testdata/importpkg/out.ll
Normal file
40
cl/_testdata/importpkg/out.ll
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
; ModuleID = 'main'
|
||||||
|
source_filename = "main"
|
||||||
|
|
||||||
|
@main.hello = global ptr null
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
|
||||||
|
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 @"github.com/goplus/llgo/cl/internal/stdio.init"()
|
||||||
|
store i8 72, ptr @main.hello, align 1
|
||||||
|
store i8 101, ptr getelementptr inbounds (i8, ptr @main.hello, i64 1), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.hello, i64 2), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.hello, i64 3), align 1
|
||||||
|
store i8 111, ptr getelementptr inbounds (i8, ptr @main.hello, i64 4), align 1
|
||||||
|
store i8 10, ptr getelementptr inbounds (i8, ptr @main.hello, i64 5), align 1
|
||||||
|
store i8 0, ptr getelementptr inbounds (i8, ptr @main.hello, i64 6), align 1
|
||||||
|
br label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @main() {
|
||||||
|
_llgo_0:
|
||||||
|
call void @main.init()
|
||||||
|
%0 = call i64 @"github.com/goplus/llgo/cl/internal/stdio.Max"(i64 2, i64 100)
|
||||||
|
call void (ptr, ...) @printf(ptr @main.hello)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/cl/internal/stdio.init"()
|
||||||
|
|
||||||
|
declare i64 @"github.com/goplus/llgo/cl/internal/stdio.Max"(i64, i64)
|
||||||
|
|
||||||
|
declare void @printf(ptr, ...)
|
||||||
19
cl/_testdata/method/in.go
Normal file
19
cl/_testdata/method/in.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import _ "unsafe"
|
||||||
|
|
||||||
|
type T int
|
||||||
|
|
||||||
|
func (a T) Add(b T) T {
|
||||||
|
return a + b
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname printf C.printf
|
||||||
|
func printf(format *int8, __llgo_va_list ...any)
|
||||||
|
|
||||||
|
var format = [...]int8{'H', 'e', 'l', 'l', 'o', ' ', '%', 'd', '\n', 0}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
a := T(1)
|
||||||
|
printf(&format[0], a.Add(2))
|
||||||
|
}
|
||||||
51
cl/_testdata/method/out.ll
Normal file
51
cl/_testdata/method/out.ll
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
; ModuleID = 'main'
|
||||||
|
source_filename = "main"
|
||||||
|
|
||||||
|
@main.format = global ptr null
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
|
||||||
|
define i64 @"(main.T).Add"(i64 %0, i64 %1) {
|
||||||
|
_llgo_0:
|
||||||
|
%2 = add i64 %0, %1
|
||||||
|
ret i64 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"(*main.T).Add"(ptr %0, i64 %1) {
|
||||||
|
_llgo_0:
|
||||||
|
%2 = load i64, ptr %0, align 4
|
||||||
|
%3 = call i64 @"(main.T).Add"(i64 %2, i64 %1)
|
||||||
|
ret i64 %3
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
store i8 72, ptr @main.format, align 1
|
||||||
|
store i8 101, ptr getelementptr inbounds (i8, ptr @main.format, i64 1), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 2), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 3), align 1
|
||||||
|
store i8 111, ptr getelementptr inbounds (i8, ptr @main.format, i64 4), align 1
|
||||||
|
store i8 32, ptr getelementptr inbounds (i8, ptr @main.format, i64 5), align 1
|
||||||
|
store i8 37, ptr getelementptr inbounds (i8, ptr @main.format, i64 6), align 1
|
||||||
|
store i8 100, ptr getelementptr inbounds (i8, ptr @main.format, i64 7), align 1
|
||||||
|
store i8 10, ptr getelementptr inbounds (i8, ptr @main.format, i64 8), align 1
|
||||||
|
store i8 0, ptr getelementptr inbounds (i8, ptr @main.format, i64 9), align 1
|
||||||
|
br label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @main() {
|
||||||
|
_llgo_0:
|
||||||
|
call void @main.init()
|
||||||
|
%0 = call i64 @"(main.T).Add"(i64 1, i64 2)
|
||||||
|
call void (ptr, ...) @printf(ptr @main.format, i64 %0)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @printf(ptr, ...)
|
||||||
@@ -2,7 +2,7 @@ package main
|
|||||||
|
|
||||||
import _ "unsafe"
|
import _ "unsafe"
|
||||||
|
|
||||||
//go:linkname printf _printf
|
//go:linkname printf C.printf
|
||||||
func printf(format *int8, __llgo_va_list ...any)
|
func printf(format *int8, __llgo_va_list ...any)
|
||||||
|
|
||||||
var hello = [...]int8{'H', 'e', 'l', 'l', 'o', '\n', 0}
|
var hello = [...]int8{'H', 'e', 'l', 'l', 'o', '\n', 0}
|
||||||
|
|||||||
@@ -1,34 +1,34 @@
|
|||||||
; ModuleID = 'main'
|
; ModuleID = 'main'
|
||||||
source_filename = "main"
|
source_filename = "main"
|
||||||
|
|
||||||
@"init$guard" = global ptr null
|
@main.hello = global ptr null
|
||||||
@hello = global ptr null
|
@"main.init$guard" = global ptr null
|
||||||
|
|
||||||
define void @init() {
|
define void @main.init() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
%0 = load i1, ptr @"init$guard", align 1
|
%0 = load i1, ptr @"main.init$guard", align 1
|
||||||
br i1 %0, label %_llgo_2, label %_llgo_1
|
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||||
|
|
||||||
_llgo_1: ; preds = %_llgo_0
|
_llgo_1: ; preds = %_llgo_0
|
||||||
store i1 true, ptr @"init$guard", align 1
|
store i1 true, ptr @"main.init$guard", align 1
|
||||||
store i8 72, ptr @hello, align 1
|
store i8 72, ptr @main.hello, align 1
|
||||||
store i8 101, ptr getelementptr inbounds (i8, ptr @hello, i64 1), align 1
|
store i8 101, ptr getelementptr inbounds (i8, ptr @main.hello, i64 1), align 1
|
||||||
store i8 108, ptr getelementptr inbounds (i8, ptr @hello, i64 2), align 1
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.hello, i64 2), align 1
|
||||||
store i8 108, ptr getelementptr inbounds (i8, ptr @hello, i64 3), align 1
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.hello, i64 3), align 1
|
||||||
store i8 111, ptr getelementptr inbounds (i8, ptr @hello, i64 4), align 1
|
store i8 111, ptr getelementptr inbounds (i8, ptr @main.hello, i64 4), align 1
|
||||||
store i8 10, ptr getelementptr inbounds (i8, ptr @hello, i64 5), align 1
|
store i8 10, ptr getelementptr inbounds (i8, ptr @main.hello, i64 5), align 1
|
||||||
store i8 0, ptr getelementptr inbounds (i8, ptr @hello, i64 6), align 1
|
store i8 0, ptr getelementptr inbounds (i8, ptr @main.hello, i64 6), align 1
|
||||||
br label %_llgo_2
|
br label %_llgo_2
|
||||||
|
|
||||||
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @printf(ptr, ...)
|
|
||||||
|
|
||||||
define void @main() {
|
define void @main() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
call void @init()
|
call void @main.init()
|
||||||
call void (ptr, ...) @printf(ptr @hello)
|
call void (ptr, ...) @printf(ptr @main.hello)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare void @printf(ptr, ...)
|
||||||
|
|||||||
12
cl/_testdata/printval/in.go
Normal file
12
cl/_testdata/printval/in.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import _ "unsafe"
|
||||||
|
|
||||||
|
//go:linkname printf C.printf
|
||||||
|
func printf(format *int8, __llgo_va_list ...any)
|
||||||
|
|
||||||
|
var format = [...]int8{'H', 'e', 'l', 'l', 'o', ' ', '%', 'd', '\n', 0}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
printf(&format[0], 100)
|
||||||
|
}
|
||||||
37
cl/_testdata/printval/out.ll
Normal file
37
cl/_testdata/printval/out.ll
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
; ModuleID = 'main'
|
||||||
|
source_filename = "main"
|
||||||
|
|
||||||
|
@main.format = global ptr null
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
|
||||||
|
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
|
||||||
|
store i8 72, ptr @main.format, align 1
|
||||||
|
store i8 101, ptr getelementptr inbounds (i8, ptr @main.format, i64 1), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 2), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 3), align 1
|
||||||
|
store i8 111, ptr getelementptr inbounds (i8, ptr @main.format, i64 4), align 1
|
||||||
|
store i8 32, ptr getelementptr inbounds (i8, ptr @main.format, i64 5), align 1
|
||||||
|
store i8 37, ptr getelementptr inbounds (i8, ptr @main.format, i64 6), align 1
|
||||||
|
store i8 100, ptr getelementptr inbounds (i8, ptr @main.format, i64 7), align 1
|
||||||
|
store i8 10, ptr getelementptr inbounds (i8, ptr @main.format, i64 8), align 1
|
||||||
|
store i8 0, ptr getelementptr inbounds (i8, ptr @main.format, i64 9), align 1
|
||||||
|
br label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @main() {
|
||||||
|
_llgo_0:
|
||||||
|
call void @main.init()
|
||||||
|
call void (ptr, ...) @printf(ptr @main.format, i64 100)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @printf(ptr, ...)
|
||||||
19
cl/_testdata/ptrmthd/in.go
Normal file
19
cl/_testdata/ptrmthd/in.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import _ "unsafe"
|
||||||
|
|
||||||
|
//go:linkname printf C.printf
|
||||||
|
func printf(format *int8, __llgo_va_list ...any)
|
||||||
|
|
||||||
|
type T int8
|
||||||
|
|
||||||
|
func (f *T) Print(v int) {
|
||||||
|
printf((*int8)(f), v)
|
||||||
|
}
|
||||||
|
|
||||||
|
var format = [...]T{'H', 'e', 'l', 'l', 'o', ' ', '%', 'd', '\n', 0}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
f := &format[0]
|
||||||
|
f.Print(100)
|
||||||
|
}
|
||||||
43
cl/_testdata/ptrmthd/out.ll
Normal file
43
cl/_testdata/ptrmthd/out.ll
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
; ModuleID = 'main'
|
||||||
|
source_filename = "main"
|
||||||
|
|
||||||
|
@main.format = global ptr null
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
|
||||||
|
define void @"(*main.T).Print"(ptr %0, i64 %1) {
|
||||||
|
_llgo_0:
|
||||||
|
call void (ptr, ...) @printf(ptr %0, i64 %1)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
store i8 72, ptr @main.format, align 1
|
||||||
|
store i8 101, ptr getelementptr inbounds (i8, ptr @main.format, i64 1), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 2), align 1
|
||||||
|
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 3), align 1
|
||||||
|
store i8 111, ptr getelementptr inbounds (i8, ptr @main.format, i64 4), align 1
|
||||||
|
store i8 32, ptr getelementptr inbounds (i8, ptr @main.format, i64 5), align 1
|
||||||
|
store i8 37, ptr getelementptr inbounds (i8, ptr @main.format, i64 6), align 1
|
||||||
|
store i8 100, ptr getelementptr inbounds (i8, ptr @main.format, i64 7), align 1
|
||||||
|
store i8 10, ptr getelementptr inbounds (i8, ptr @main.format, i64 8), align 1
|
||||||
|
store i8 0, ptr getelementptr inbounds (i8, ptr @main.format, i64 9), align 1
|
||||||
|
br label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @main() {
|
||||||
|
_llgo_0:
|
||||||
|
call void @main.init()
|
||||||
|
call void @"(*main.T).Print"(ptr @main.format, i64 100)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @printf(ptr, ...)
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
; ModuleID = 'main'
|
; ModuleID = 'main'
|
||||||
source_filename = "main"
|
source_filename = "main"
|
||||||
|
|
||||||
@"init$guard" = global ptr null
|
@main.a = global ptr null
|
||||||
@a = global ptr null
|
@"main.init$guard" = global ptr null
|
||||||
|
|
||||||
define void @init() {
|
define void @main.init() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
%0 = load i1, ptr @"init$guard", align 1
|
%0 = load i1, ptr @"main.init$guard", align 1
|
||||||
br i1 %0, label %_llgo_2, label %_llgo_1
|
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||||
|
|
||||||
_llgo_1: ; preds = %_llgo_0
|
_llgo_1: ; preds = %_llgo_0
|
||||||
store i1 true, ptr @"init$guard", align 1
|
store i1 true, ptr @"main.init$guard", align 1
|
||||||
store i64 100, ptr @a, align 4
|
store i64 100, ptr @main.a, align 4
|
||||||
br label %_llgo_2
|
br label %_llgo_2
|
||||||
|
|
||||||
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
@@ -20,10 +20,10 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
|
|||||||
|
|
||||||
define void @main() {
|
define void @main() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
call void @init()
|
call void @main.init()
|
||||||
%0 = load i64, ptr @a, align 4
|
%0 = load i64, ptr @main.a, align 4
|
||||||
%1 = add i64 %0, 1
|
%1 = add i64 %0, 1
|
||||||
store i64 %1, ptr @a, align 4
|
store i64 %1, ptr @main.a, align 4
|
||||||
%2 = load i64, ptr @a, align 4
|
%2 = load i64, ptr @main.a, align 4
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|||||||
80
cl/builtin_test.go
Normal file
80
cl/builtin_test.go
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* 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 cl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/types"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
llssa "github.com/goplus/llgo/ssa"
|
||||||
|
"golang.org/x/tools/go/ssa"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIsAny(t *testing.T) {
|
||||||
|
if isAny(types.Typ[types.UntypedInt]) {
|
||||||
|
t.Fatal("isAny?")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntVal(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r == nil {
|
||||||
|
t.Fatal("intVal: no error?")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
intVal(&ssa.Parameter{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIgnoreName(t *testing.T) {
|
||||||
|
if !ignoreName("runtime.foo") || !ignoreName("runtime/foo") || !ignoreName("internal/abi") {
|
||||||
|
t.Fatal("ignoreName failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErrImport(t *testing.T) {
|
||||||
|
var ctx context
|
||||||
|
pkg := types.NewPackage("foo", "foo")
|
||||||
|
ctx.importPkg(pkg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErrInitLinkname(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r == nil {
|
||||||
|
t.Fatal("initLinkname: no error?")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
var ctx context
|
||||||
|
ctx.initLinkname("foo", "//go:linkname Printf printf")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErrVarOf(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r == nil {
|
||||||
|
t.Fatal("varOf: no error?")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
prog := llssa.NewProgram(nil)
|
||||||
|
pkg := prog.NewPackage("foo", "foo")
|
||||||
|
pkgTypes := types.NewPackage("foo", "foo")
|
||||||
|
ctx := &context{
|
||||||
|
pkg: pkg,
|
||||||
|
goTyps: pkgTypes,
|
||||||
|
}
|
||||||
|
ssaPkg := &ssa.Package{Pkg: pkgTypes}
|
||||||
|
g := &ssa.Global{Pkg: ssaPkg}
|
||||||
|
ctx.varOf(g)
|
||||||
|
}
|
||||||
123
cl/cltest/cltest.go
Normal file
123
cl/cltest/cltest.go
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* 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 cltest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/ast"
|
||||||
|
"go/parser"
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/goplus/gogen/packages"
|
||||||
|
"github.com/goplus/llgo/cl"
|
||||||
|
"github.com/goplus/llgo/internal/llgen"
|
||||||
|
"golang.org/x/tools/go/ssa"
|
||||||
|
"golang.org/x/tools/go/ssa/ssautil"
|
||||||
|
|
||||||
|
llssa "github.com/goplus/llgo/ssa"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
cl.SetDebug(cl.DbgFlagAll)
|
||||||
|
llssa.Initialize(llssa.InitAll)
|
||||||
|
llssa.SetDebug(llssa.DbgFlagAll)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromDir(t *testing.T, sel, relDir string, byLLGen bool) {
|
||||||
|
dir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Getwd failed:", err)
|
||||||
|
}
|
||||||
|
dir = path.Join(dir, relDir)
|
||||||
|
fis, err := os.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("ReadDir failed:", err)
|
||||||
|
}
|
||||||
|
for _, fi := range fis {
|
||||||
|
name := fi.Name()
|
||||||
|
if !fi.IsDir() || strings.HasPrefix(name, "_") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
testFrom(t, dir+"/"+name, sel, byLLGen)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Pkg(t *testing.T, pkgPath, outFile string) {
|
||||||
|
b, err := os.ReadFile(outFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("ReadFile failed:", err)
|
||||||
|
}
|
||||||
|
expected := string(b)
|
||||||
|
if v := llgen.GenFrom(pkgPath); v != expected {
|
||||||
|
t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFrom(t *testing.T, pkgDir, sel string, byLLGen bool) {
|
||||||
|
if sel != "" && !strings.Contains(pkgDir, sel) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Println("Parsing", pkgDir)
|
||||||
|
in := pkgDir + "/in.go"
|
||||||
|
out := pkgDir + "/out.ll"
|
||||||
|
b, err := os.ReadFile(out)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("ReadFile failed:", err)
|
||||||
|
}
|
||||||
|
expected := string(b)
|
||||||
|
if byLLGen {
|
||||||
|
if v := llgen.GenFrom(in); v != expected {
|
||||||
|
t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TestCompileEx(t, nil, in, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompileEx(t *testing.T, src any, fname, expected string) {
|
||||||
|
t.Helper()
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
f, err := parser.ParseFile(fset, fname, src, parser.ParseComments)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("ParseFile failed:", err)
|
||||||
|
}
|
||||||
|
files := []*ast.File{f}
|
||||||
|
name := f.Name.Name
|
||||||
|
pkg := types.NewPackage(name, name)
|
||||||
|
imp := packages.NewImporter(fset)
|
||||||
|
foo, _, err := ssautil.BuildPackage(
|
||||||
|
&types.Config{Importer: imp}, fset, pkg, files, ssa.SanityCheckFunctions)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("BuildPackage failed:", err)
|
||||||
|
}
|
||||||
|
foo.WriteTo(os.Stderr)
|
||||||
|
prog := llssa.NewProgram(nil)
|
||||||
|
ret, err := cl.NewPackage(prog, foo, files)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("cl.NewPackage failed:", err)
|
||||||
|
}
|
||||||
|
if v := ret.String(); v != expected {
|
||||||
|
t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
288
cl/compile.go
288
cl/compile.go
@@ -18,9 +18,14 @@ package cl
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
|
"go/constant"
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
llssa "github.com/goplus/llgo/ssa"
|
llssa "github.com/goplus/llgo/ssa"
|
||||||
"golang.org/x/tools/go/ssa"
|
"golang.org/x/tools/go/ssa"
|
||||||
@@ -53,18 +58,19 @@ func SetDebug(dbgFlags dbgFlags) {
|
|||||||
const (
|
const (
|
||||||
fnNormal = iota
|
fnNormal = iota
|
||||||
fnHasVArg
|
fnHasVArg
|
||||||
fnUnsafeInit
|
fnIgnore
|
||||||
)
|
)
|
||||||
|
|
||||||
func funcKind(vfn ssa.Value) int {
|
func funcKind(vfn ssa.Value) int {
|
||||||
if fn, ok := vfn.(*ssa.Function); ok {
|
if fn, ok := vfn.(*ssa.Function); ok && fn.Signature.Recv() == nil {
|
||||||
n := len(fn.Params)
|
params := fn.Signature.Params()
|
||||||
|
n := params.Len()
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
if fn.Name() == "init" && fn.Pkg.Pkg.Path() == "unsafe" {
|
if fn.Name() == "init" && ignorePkgInit(fn.Pkg.Pkg.Path()) {
|
||||||
return fnUnsafeInit
|
return fnIgnore
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
last := fn.Params[n-1]
|
last := params.At(n - 1)
|
||||||
if last.Name() == llssa.NameValist {
|
if last.Name() == llssa.NameValist {
|
||||||
return fnHasVArg
|
return fnHasVArg
|
||||||
}
|
}
|
||||||
@@ -73,13 +79,43 @@ func funcKind(vfn ssa.Value) int {
|
|||||||
return fnNormal
|
return fnNormal
|
||||||
}
|
}
|
||||||
|
|
||||||
func isMainFunc(fn *ssa.Function) bool {
|
func ignorePkgInit(pkgPath string) bool {
|
||||||
return fn.Name() == "main" && fn.Pkg.Pkg.Path() == "main"
|
switch pkgPath {
|
||||||
|
case "unsafe", "syscall", "runtime/cgo":
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func ignoreName(name string) bool {
|
||||||
|
/* TODO(xsw): confirm this is not needed more
|
||||||
|
if name == "unsafe.init" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if strings.HasPrefix(name, "internal/") || strings.HasPrefix(name, "crypto/") ||
|
||||||
|
strings.HasPrefix(name, "arena.") || strings.HasPrefix(name, "maps.") ||
|
||||||
|
strings.HasPrefix(name, "time.") || strings.HasPrefix(name, "syscall.") ||
|
||||||
|
strings.HasPrefix(name, "os.") || strings.HasPrefix(name, "plugin.") ||
|
||||||
|
strings.HasPrefix(name, "reflect.") || strings.HasPrefix(name, "errors.") {
|
||||||
|
return true // TODO(xsw)
|
||||||
|
}
|
||||||
|
return inPkg(name, "runtime") || inPkg(name, "sync")
|
||||||
|
}
|
||||||
|
|
||||||
|
func inPkg(name, pkg string) bool {
|
||||||
|
if len(name) > len(pkg) && strings.HasPrefix(name, pkg) {
|
||||||
|
c := name[len(pkg)]
|
||||||
|
return c == '.' || c == '/'
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
type instrAndValue interface {
|
type none = struct{}
|
||||||
|
|
||||||
|
type instrOrValue interface {
|
||||||
ssa.Instruction
|
ssa.Instruction
|
||||||
ssa.Value
|
ssa.Value
|
||||||
}
|
}
|
||||||
@@ -88,18 +124,53 @@ type context struct {
|
|||||||
prog llssa.Program
|
prog llssa.Program
|
||||||
pkg llssa.Package
|
pkg llssa.Package
|
||||||
fn llssa.Function
|
fn llssa.Function
|
||||||
|
fset *token.FileSet
|
||||||
|
goProg *ssa.Program
|
||||||
|
goTyps *types.Package
|
||||||
goPkg *ssa.Package
|
goPkg *ssa.Package
|
||||||
|
link map[string]string // pkgPath.nameInPkg => linkname
|
||||||
|
loaded map[*types.Package]none // 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
|
||||||
inits []func()
|
inits []func()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) compileType(pkg llssa.Package, member *ssa.Type) {
|
func (p *context) compileType(pkg llssa.Package, t *ssa.Type) {
|
||||||
panic("todo")
|
tn := t.Object().(*types.TypeName)
|
||||||
|
if tn.IsAlias() { // don't need to compile alias type
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tnName := tn.Name()
|
||||||
|
typ := tn.Type()
|
||||||
|
name := llssa.FullName(tn.Pkg(), tnName)
|
||||||
|
if ignoreName(name) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if debugInstr {
|
||||||
|
log.Println("==> NewType", name, typ)
|
||||||
|
}
|
||||||
|
p.compileMethods(pkg, typ)
|
||||||
|
p.compileMethods(pkg, types.NewPointer(typ))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) compileMethods(pkg llssa.Package, typ types.Type) {
|
||||||
|
prog := p.goProg
|
||||||
|
mthds := prog.MethodSets.MethodSet(typ)
|
||||||
|
for i, n := 0, mthds.Len(); i < n; i++ {
|
||||||
|
mthd := mthds.At(i)
|
||||||
|
if ssaMthd := prog.MethodValue(mthd); ssaMthd != nil {
|
||||||
|
p.compileFunc(pkg, mthd.Obj().Pkg(), ssaMthd)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global variable.
|
// Global variable.
|
||||||
func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) {
|
func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) {
|
||||||
name, typ := gbl.Name(), gbl.Type()
|
typ := gbl.Type()
|
||||||
|
name := llssa.FullName(gbl.Pkg.Pkg, gbl.Name())
|
||||||
|
if ignoreName(name) || checkCgo(gbl.Name()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
log.Println("==> NewVar", name, typ)
|
log.Println("==> NewVar", name, typ)
|
||||||
}
|
}
|
||||||
@@ -107,12 +178,16 @@ func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) {
|
|||||||
g.Init(p.prog.Null(g.Type))
|
g.Init(p.prog.Null(g.Type))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) compileFunc(pkg llssa.Package, f *ssa.Function) {
|
func (p *context) compileFunc(pkg llssa.Package, pkgTypes *types.Package, f *ssa.Function) {
|
||||||
name := f.Name()
|
sig := f.Signature
|
||||||
if debugInstr {
|
name, ok := p.funcName(pkgTypes, f, true)
|
||||||
log.Println("==> NewFunc", name)
|
if !ok { // ignored
|
||||||
|
return
|
||||||
}
|
}
|
||||||
fn := pkg.NewFunc(name, f.Signature)
|
if debugInstr {
|
||||||
|
log.Println("==> NewFunc", name, "type:", sig.Recv(), sig)
|
||||||
|
}
|
||||||
|
fn := pkg.NewFunc(name, sig)
|
||||||
p.inits = append(p.inits, func() {
|
p.inits = append(p.inits, func() {
|
||||||
p.fn = fn
|
p.fn = fn
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -130,9 +205,9 @@ func (p *context) compileFunc(pkg llssa.Package, f *ssa.Function) {
|
|||||||
}
|
}
|
||||||
fn.MakeBlocks(nblk)
|
fn.MakeBlocks(nblk)
|
||||||
b := fn.NewBuilder()
|
b := fn.NewBuilder()
|
||||||
isMain := isMainFunc(f)
|
p.bvals = make(map[ssa.Value]llssa.Expr)
|
||||||
for i, block := range f.Blocks {
|
for i, block := range f.Blocks {
|
||||||
p.compileBlock(b, block, isMain && i == 0)
|
p.compileBlock(b, block, i == 0 && name == "main")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -140,9 +215,8 @@ func (p *context) compileFunc(pkg llssa.Package, f *ssa.Function) {
|
|||||||
func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, doInit bool) llssa.BasicBlock {
|
func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, doInit bool) llssa.BasicBlock {
|
||||||
ret := p.fn.Block(block.Index)
|
ret := p.fn.Block(block.Index)
|
||||||
b.SetBlock(ret)
|
b.SetBlock(ret)
|
||||||
p.bvals = make(map[ssa.Value]llssa.Expr)
|
|
||||||
if doInit {
|
if doInit {
|
||||||
fn := p.pkg.FuncOf("init")
|
fn := p.pkg.FuncOf("main.init")
|
||||||
b.Call(fn.Expr)
|
b.Call(fn.Expr)
|
||||||
}
|
}
|
||||||
for _, instr := range block.Instrs {
|
for _, instr := range block.Instrs {
|
||||||
@@ -151,23 +225,74 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, doInit bo
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret llssa.Expr) {
|
func isAny(t types.Type) bool {
|
||||||
|
if t, ok := t.(*types.Interface); ok {
|
||||||
|
return t.Empty()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func intVal(v ssa.Value) int64 {
|
||||||
|
if c, ok := v.(*ssa.Const); ok {
|
||||||
|
if iv, exact := constant.Int64Val(c.Value); exact {
|
||||||
|
return iv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("intVal: ssa.Value is not a const int")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) isVArgs(vx ssa.Value) (ret []llssa.Expr, ok bool) {
|
||||||
|
if va, vok := vx.(*ssa.Alloc); vok {
|
||||||
|
ret, ok = p.vargs[va] // varargs: this is a varargs index
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) checkVArgs(v *ssa.Alloc, t *types.Pointer) bool {
|
||||||
|
if v.Comment == "varargs" { // this is a varargs allocation
|
||||||
|
if arr, ok := t.Elem().(*types.Array); ok {
|
||||||
|
if isAny(arr.Elem()) {
|
||||||
|
p.vargs[v] = make([]llssa.Expr, arr.Len())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue bool) (ret llssa.Expr) {
|
||||||
|
if asValue {
|
||||||
if v, ok := p.bvals[iv]; ok {
|
if v, ok := p.bvals[iv]; ok {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
log.Panicln("unreachable:", iv)
|
||||||
|
}
|
||||||
switch v := iv.(type) {
|
switch v := iv.(type) {
|
||||||
case *ssa.Call:
|
case *ssa.Call:
|
||||||
call := v.Call
|
call := v.Call
|
||||||
kind := funcKind(call.Value)
|
cv := call.Value
|
||||||
if kind == fnUnsafeInit {
|
kind := funcKind(cv)
|
||||||
|
if kind == fnIgnore {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if debugGoSSA {
|
if debugGoSSA {
|
||||||
log.Println(">>> Call", call.Value, call.Args)
|
log.Println(">>> Call", cv, call.Args)
|
||||||
}
|
}
|
||||||
fn := p.compileValue(b, call.Value)
|
if builtin, ok := cv.(*ssa.Builtin); ok {
|
||||||
|
fn := builtin.Name()
|
||||||
|
if fn == "ssa:wrapnilchk" { // TODO(xsw): check nil ptr
|
||||||
|
arg := call.Args[0]
|
||||||
|
ret = p.compileValue(b, arg)
|
||||||
|
// log.Println("wrapnilchk:", ret.TypeOf())
|
||||||
|
} else {
|
||||||
|
args := p.compileValues(b, call.Args, kind)
|
||||||
|
ret = b.BuiltinCall(fn, args...)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fn := p.compileValue(b, cv)
|
||||||
args := p.compileValues(b, call.Args, kind)
|
args := p.compileValues(b, call.Args, kind)
|
||||||
ret = b.Call(fn, args...)
|
ret = b.Call(fn, args...)
|
||||||
|
}
|
||||||
case *ssa.BinOp:
|
case *ssa.BinOp:
|
||||||
x := p.compileValue(b, v.X)
|
x := p.compileValue(b, v.X)
|
||||||
y := p.compileValue(b, v.Y)
|
y := p.compileValue(b, v.Y)
|
||||||
@@ -175,13 +300,47 @@ func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret l
|
|||||||
case *ssa.UnOp:
|
case *ssa.UnOp:
|
||||||
x := p.compileValue(b, v.X)
|
x := p.compileValue(b, v.X)
|
||||||
ret = b.UnOp(v.Op, x)
|
ret = b.UnOp(v.Op, x)
|
||||||
case *ssa.IndexAddr:
|
case *ssa.ChangeType:
|
||||||
|
t := v.Type()
|
||||||
x := p.compileValue(b, v.X)
|
x := p.compileValue(b, v.X)
|
||||||
|
ret = b.ChangeType(p.prog.Type(t), x)
|
||||||
|
case *ssa.Convert:
|
||||||
|
t := v.Type()
|
||||||
|
x := p.compileValue(b, v.X)
|
||||||
|
ret = b.Convert(p.prog.Type(t), x)
|
||||||
|
case *ssa.FieldAddr:
|
||||||
|
x := p.compileValue(b, v.X)
|
||||||
|
ret = b.FieldAddr(x, v.Field)
|
||||||
|
case *ssa.IndexAddr:
|
||||||
|
vx := v.X
|
||||||
|
if _, ok := p.isVArgs(vx); ok { // varargs: this is a varargs index
|
||||||
|
return
|
||||||
|
}
|
||||||
|
x := p.compileValue(b, vx)
|
||||||
idx := p.compileValue(b, v.Index)
|
idx := p.compileValue(b, v.Index)
|
||||||
ret = b.IndexAddr(x, idx)
|
ret = b.IndexAddr(x, idx)
|
||||||
|
case *ssa.Slice:
|
||||||
|
vx := v.X
|
||||||
|
if _, ok := p.isVArgs(vx); ok { // varargs: this is a varargs slice
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic("todo")
|
||||||
case *ssa.Alloc:
|
case *ssa.Alloc:
|
||||||
|
t := v.Type().(*types.Pointer)
|
||||||
|
if p.checkVArgs(v, t) { // varargs: this is a varargs allocation
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ret = b.Alloc(t, v.Heap)
|
||||||
|
case *ssa.MakeInterface:
|
||||||
|
const (
|
||||||
|
delayExpr = true // varargs: don't need to convert an expr to any
|
||||||
|
)
|
||||||
t := v.Type()
|
t := v.Type()
|
||||||
ret = b.Alloc(p.prog.Type(t), v.Heap)
|
x := p.compileValue(b, v.X)
|
||||||
|
ret = b.MakeInterface(t, x, delayExpr)
|
||||||
|
case *ssa.TypeAssert:
|
||||||
|
x := p.compileValue(b, v.X)
|
||||||
|
ret = b.TypeAssert(x, p.prog.Type(v.AssertedType), v.CommaOk)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("compileInstrAndValue: unknown instr - %T\n", iv))
|
panic(fmt.Sprintf("compileInstrAndValue: unknown instr - %T\n", iv))
|
||||||
}
|
}
|
||||||
@@ -190,13 +349,25 @@ func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret l
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
|
func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
|
||||||
if iv, ok := instr.(instrAndValue); ok {
|
if iv, ok := instr.(instrOrValue); ok {
|
||||||
p.compileInstrAndValue(b, iv)
|
p.compileInstrOrValue(b, iv, false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch v := instr.(type) {
|
switch v := instr.(type) {
|
||||||
case *ssa.Store:
|
case *ssa.Store:
|
||||||
ptr := p.compileValue(b, v.Addr)
|
va := v.Addr
|
||||||
|
if va, ok := va.(*ssa.IndexAddr); ok {
|
||||||
|
if args, ok := p.isVArgs(va.X); ok { // varargs: this is a varargs store
|
||||||
|
idx := intVal(va.Index)
|
||||||
|
val := v.Val
|
||||||
|
if vi, ok := val.(*ssa.MakeInterface); ok {
|
||||||
|
val = vi.X
|
||||||
|
}
|
||||||
|
args[idx] = p.compileValue(b, val)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptr := p.compileValue(b, va)
|
||||||
val := p.compileValue(b, v.Val)
|
val := p.compileValue(b, v.Val)
|
||||||
b.Store(ptr, val)
|
b.Store(ptr, val)
|
||||||
case *ssa.Jump:
|
case *ssa.Jump:
|
||||||
@@ -220,14 +391,17 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
|
|||||||
thenb := fn.Block(succs[0].Index)
|
thenb := fn.Block(succs[0].Index)
|
||||||
elseb := fn.Block(succs[1].Index)
|
elseb := fn.Block(succs[1].Index)
|
||||||
b.If(cond, thenb, elseb)
|
b.If(cond, thenb, elseb)
|
||||||
|
case *ssa.Panic:
|
||||||
|
arg := p.compileValue(b, v.X).Do()
|
||||||
|
b.Panic(arg)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("compileInstr: unknown instr - %T\n", instr))
|
panic(fmt.Sprintf("compileInstr: unknown instr - %T\n", instr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr {
|
func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr {
|
||||||
if iv, ok := v.(instrAndValue); ok {
|
if iv, ok := v.(instrOrValue); ok {
|
||||||
return p.compileInstrAndValue(b, iv)
|
return p.compileInstrOrValue(b, iv, true)
|
||||||
}
|
}
|
||||||
switch v := v.(type) {
|
switch v := v.(type) {
|
||||||
case *ssa.Parameter:
|
case *ssa.Parameter:
|
||||||
@@ -238,16 +412,10 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *ssa.Function:
|
case *ssa.Function:
|
||||||
if v.Pkg != p.goPkg {
|
fn := p.funcOf(v)
|
||||||
panic("todo")
|
|
||||||
}
|
|
||||||
fn := p.pkg.FuncOf(v.Name())
|
|
||||||
return fn.Expr
|
return fn.Expr
|
||||||
case *ssa.Global:
|
case *ssa.Global:
|
||||||
if v.Pkg != p.goPkg {
|
g := p.varOf(v)
|
||||||
panic("todo")
|
|
||||||
}
|
|
||||||
g := p.pkg.VarOf(v.Name())
|
|
||||||
return g.Expr
|
return g.Expr
|
||||||
case *ssa.Const:
|
case *ssa.Const:
|
||||||
t := v.Type()
|
t := v.Type()
|
||||||
@@ -259,19 +427,23 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr {
|
|||||||
func (p *context) compileVArg(ret []llssa.Expr, b llssa.Builder, v ssa.Value) []llssa.Expr {
|
func (p *context) compileVArg(ret []llssa.Expr, b llssa.Builder, v ssa.Value) []llssa.Expr {
|
||||||
_ = b
|
_ = b
|
||||||
switch v := v.(type) {
|
switch v := v.(type) {
|
||||||
|
case *ssa.Slice: // varargs: this is a varargs slice
|
||||||
|
if args, ok := p.isVArgs(v.X); ok {
|
||||||
|
return append(ret, args...)
|
||||||
|
}
|
||||||
case *ssa.Const:
|
case *ssa.Const:
|
||||||
if v.Value == nil {
|
if v.Value == nil {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic("todo")
|
panic(fmt.Sprintf("compileVArg: unknown value - %T\n", v))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) compileValues(b llssa.Builder, vals []ssa.Value, hasVArg int) []llssa.Expr {
|
func (p *context) compileValues(b llssa.Builder, vals []ssa.Value, hasVArg int) []llssa.Expr {
|
||||||
n := len(vals) - hasVArg
|
n := len(vals) - hasVArg
|
||||||
ret := make([]llssa.Expr, n)
|
ret := make([]llssa.Expr, n)
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
ret[i] = p.compileValue(b, vals[i])
|
ret[i] = p.compileValue(b, vals[i]).Do()
|
||||||
}
|
}
|
||||||
if hasVArg > 0 {
|
if hasVArg > 0 {
|
||||||
ret = p.compileVArg(ret, b, vals[n])
|
ret = p.compileVArg(ret, b, vals[n])
|
||||||
@@ -281,37 +453,41 @@ func (p *context) compileValues(b llssa.Builder, vals []ssa.Value, hasVArg int)
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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, conf *Config) (ret llssa.Package, err error) {
|
func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret llssa.Package, err error) {
|
||||||
type namedMember struct {
|
type namedMember struct {
|
||||||
name string
|
name string
|
||||||
val ssa.Member
|
val ssa.Member
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort by position, so that the order of the functions in the IR matches
|
members := make([]*namedMember, 0, len(pkg.Members))
|
||||||
// the order of functions in the source file. This is useful for testing,
|
|
||||||
// for example.
|
|
||||||
var members []*namedMember
|
|
||||||
for name, v := range pkg.Members {
|
for name, v := range pkg.Members {
|
||||||
members = append(members, &namedMember{name, v})
|
members = append(members, &namedMember{name, v})
|
||||||
}
|
}
|
||||||
sort.Slice(members, func(i, j int) bool {
|
sort.Slice(members, func(i, j int) bool {
|
||||||
iPos := members[i].val.Pos()
|
return members[i].name < members[j].name
|
||||||
jPos := members[j].val.Pos()
|
|
||||||
return iPos < jPos
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
pkgProg := pkg.Prog
|
||||||
pkgTypes := pkg.Pkg
|
pkgTypes := pkg.Pkg
|
||||||
ret = prog.NewPackage(pkgTypes.Name(), pkgTypes.Path())
|
pkgName, pkgPath := pkgTypes.Name(), llssa.PathOf(pkgTypes)
|
||||||
|
if pkgPath == llssa.PkgRuntime {
|
||||||
|
prog.SetRuntime(pkgTypes)
|
||||||
|
}
|
||||||
|
ret = prog.NewPackage(pkgName, pkgPath)
|
||||||
|
|
||||||
ctx := &context{
|
ctx := &context{
|
||||||
prog: prog,
|
prog: prog,
|
||||||
pkg: ret,
|
pkg: ret,
|
||||||
|
fset: pkgProg.Fset,
|
||||||
|
goProg: pkgProg,
|
||||||
|
goTyps: pkgTypes,
|
||||||
goPkg: pkg,
|
goPkg: pkg,
|
||||||
|
link: make(map[string]string),
|
||||||
|
loaded: make(map[*types.Package]none),
|
||||||
|
vargs: make(map[*ssa.Alloc][]llssa.Expr),
|
||||||
}
|
}
|
||||||
|
ctx.initFiles(pkgPath, files)
|
||||||
for _, m := range members {
|
for _, m := range members {
|
||||||
member := m.val
|
member := m.val
|
||||||
switch member := member.(type) {
|
switch member := member.(type) {
|
||||||
@@ -320,7 +496,7 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, conf *Config) (ret llssa.P
|
|||||||
// Do not try to build generic (non-instantiated) functions.
|
// Do not try to build generic (non-instantiated) functions.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ctx.compileFunc(ret, member)
|
ctx.compileFunc(ret, member.Pkg.Pkg, member)
|
||||||
case *ssa.Type:
|
case *ssa.Type:
|
||||||
ctx.compileType(ret, member)
|
ctx.compileType(ret, member)
|
||||||
case *ssa.Global:
|
case *ssa.Global:
|
||||||
|
|||||||
@@ -14,99 +14,30 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package cl
|
package cl_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go/ast"
|
|
||||||
"go/importer"
|
|
||||||
"go/parser"
|
|
||||||
"go/token"
|
|
||||||
"go/types"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
llssa "github.com/goplus/llgo/ssa"
|
"github.com/goplus/llgo/cl/cltest"
|
||||||
"golang.org/x/tools/go/ssa"
|
"github.com/goplus/llgo/ssa"
|
||||||
"golang.org/x/tools/go/ssa/ssautil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFromTestdata(t *testing.T) {
|
|
||||||
testFromDir(t, "", "./_testdata")
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
SetDebug(DbgFlagAll)
|
|
||||||
llssa.Initialize(llssa.InitAll)
|
|
||||||
llssa.SetDebug(llssa.DbgFlagAll)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testFromDir(t *testing.T, sel, relDir string) {
|
|
||||||
dir, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("Getwd failed:", err)
|
|
||||||
}
|
|
||||||
dir = path.Join(dir, relDir)
|
|
||||||
fis, err := os.ReadDir(dir)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("ReadDir failed:", err)
|
|
||||||
}
|
|
||||||
for _, fi := range fis {
|
|
||||||
name := fi.Name()
|
|
||||||
if !fi.IsDir() || strings.HasPrefix(name, "_") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
testFrom(t, dir+"/"+name, sel)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testFrom(t *testing.T, pkgDir, sel string) {
|
|
||||||
if sel != "" && !strings.Contains(pkgDir, sel) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Println("Parsing", pkgDir)
|
|
||||||
in := pkgDir + "/in.go"
|
|
||||||
out := pkgDir + "/out.ll"
|
|
||||||
expected, err := os.ReadFile(out)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("ReadFile failed:", err)
|
|
||||||
}
|
|
||||||
testCompileEx(t, nil, in, string(expected))
|
|
||||||
}
|
|
||||||
|
|
||||||
func testCompileEx(t *testing.T, src any, fname, expected string) {
|
|
||||||
t.Helper()
|
|
||||||
fset := token.NewFileSet()
|
|
||||||
f, err := parser.ParseFile(fset, fname, src, parser.ParseComments)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("ParseFile failed:", err)
|
|
||||||
}
|
|
||||||
files := []*ast.File{f}
|
|
||||||
name := f.Name.Name
|
|
||||||
pkg := types.NewPackage(name, name)
|
|
||||||
foo, _, err := ssautil.BuildPackage(
|
|
||||||
&types.Config{Importer: importer.Default()}, fset, pkg, files, ssa.SanityCheckFunctions)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("BuildPackage failed:", err)
|
|
||||||
}
|
|
||||||
foo.WriteTo(os.Stderr)
|
|
||||||
prog := llssa.NewProgram(nil)
|
|
||||||
ret, err := NewPackage(prog, foo, nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("cl.NewPackage failed:", err)
|
|
||||||
}
|
|
||||||
if v := ret.String(); v != expected {
|
|
||||||
t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testCompile(t *testing.T, src, expected string) {
|
func testCompile(t *testing.T, src, expected string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
testCompileEx(t, src, "foo.go", expected)
|
cltest.TestCompileEx(t, src, "foo.go", expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFromTestcgo(t *testing.T) {
|
||||||
|
cltest.FromDir(t, "", "./_testcgo", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFromTestdata(t *testing.T) {
|
||||||
|
cltest.FromDir(t, "", "./_testdata", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRuntime(t *testing.T) {
|
||||||
|
cltest.Pkg(t, ssa.PkgRuntime, "../internal/runtime/llgo_autogen.ll")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVar(t *testing.T) {
|
func TestVar(t *testing.T) {
|
||||||
@@ -116,16 +47,16 @@ var a int
|
|||||||
`, `; ModuleID = 'foo'
|
`, `; ModuleID = 'foo'
|
||||||
source_filename = "foo"
|
source_filename = "foo"
|
||||||
|
|
||||||
@"init$guard" = global ptr null
|
@foo.a = global ptr null
|
||||||
@a = global ptr null
|
@"foo.init$guard" = global ptr null
|
||||||
|
|
||||||
define void @init() {
|
define void @foo.init() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
%0 = load i1, ptr @"init$guard", align 1
|
%0 = load i1, ptr @"foo.init$guard", align 1
|
||||||
br i1 %0, label %_llgo_2, label %_llgo_1
|
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||||
|
|
||||||
_llgo_1: ; preds = %_llgo_0
|
_llgo_1: ; preds = %_llgo_0
|
||||||
store i1 true, ptr @"init$guard", align 1
|
store i1 true, ptr @"foo.init$guard", align 1
|
||||||
br label %_llgo_2
|
br label %_llgo_2
|
||||||
|
|
||||||
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
@@ -143,24 +74,24 @@ func fn(a int, b float64) int {
|
|||||||
`, `; ModuleID = 'foo'
|
`, `; ModuleID = 'foo'
|
||||||
source_filename = "foo"
|
source_filename = "foo"
|
||||||
|
|
||||||
@"init$guard" = global ptr null
|
@"foo.init$guard" = global ptr null
|
||||||
|
|
||||||
define void @init() {
|
define i64 @foo.fn(i64 %0, double %1) {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
%0 = load i1, ptr @"init$guard", align 1
|
ret i64 1
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @foo.init() {
|
||||||
|
_llgo_0:
|
||||||
|
%0 = load i1, ptr @"foo.init$guard", align 1
|
||||||
br i1 %0, label %_llgo_2, label %_llgo_1
|
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||||
|
|
||||||
_llgo_1: ; preds = %_llgo_0
|
_llgo_1: ; preds = %_llgo_0
|
||||||
store i1 true, ptr @"init$guard", align 1
|
store i1 true, ptr @"foo.init$guard", align 1
|
||||||
br label %_llgo_2
|
br label %_llgo_2
|
||||||
|
|
||||||
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
define i64 @fn(i64 %0, double %1) {
|
|
||||||
_llgo_0:
|
|
||||||
ret i64 1
|
|
||||||
}
|
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|||||||
178
cl/import.go
Normal file
178
cl/import.go
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
* 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 cl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"go/ast"
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
llssa "github.com/goplus/llgo/ssa"
|
||||||
|
"golang.org/x/tools/go/ssa"
|
||||||
|
)
|
||||||
|
|
||||||
|
type contentLines = [][]byte
|
||||||
|
type contentMap = map[string]contentLines
|
||||||
|
|
||||||
|
func contentOf(m contentMap, file string) (lines contentLines, err error) {
|
||||||
|
if v, ok := m[file]; ok {
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
b, err := os.ReadFile(file)
|
||||||
|
if err == nil {
|
||||||
|
lines = bytes.Split(b, []byte{'\n'})
|
||||||
|
m[file] = lines
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) importPkg(pkg *types.Package) {
|
||||||
|
scope := pkg.Scope()
|
||||||
|
if scope.Lookup("LLGoPackage") == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fset := p.fset
|
||||||
|
names := scope.Names()
|
||||||
|
contents := make(contentMap)
|
||||||
|
pkgPath := llssa.PathOf(pkg)
|
||||||
|
for _, name := range names {
|
||||||
|
if token.IsExported(name) {
|
||||||
|
obj := scope.Lookup(name)
|
||||||
|
if obj, ok := obj.(*types.Func); ok {
|
||||||
|
if pos := obj.Pos(); pos != token.NoPos {
|
||||||
|
f := fset.File(pos)
|
||||||
|
if fp := f.Position(pos); fp.Line > 2 {
|
||||||
|
lines, err := contentOf(contents, fp.Filename)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if i := fp.Line - 2; i < len(lines) {
|
||||||
|
line := string(lines[i])
|
||||||
|
p.initLinkname(pkgPath, line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) initFiles(pkgPath string, files []*ast.File) {
|
||||||
|
for _, file := range files {
|
||||||
|
for _, decl := range file.Decls {
|
||||||
|
if decl, ok := decl.(*ast.FuncDecl); ok {
|
||||||
|
if decl.Recv == nil {
|
||||||
|
if doc := decl.Doc; doc != nil {
|
||||||
|
if n := len(doc.List); n > 0 {
|
||||||
|
line := doc.List[n-1].Text
|
||||||
|
p.initLinkname(pkgPath, line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) initLinkname(pkgPath, line string) {
|
||||||
|
const (
|
||||||
|
linkname = "//go:linkname "
|
||||||
|
)
|
||||||
|
if strings.HasPrefix(line, linkname) {
|
||||||
|
text := strings.TrimSpace(line[len(linkname):])
|
||||||
|
if idx := strings.IndexByte(text, ' '); idx > 0 {
|
||||||
|
link := strings.TrimLeft(text[idx+1:], " ")
|
||||||
|
if strings.Contains(link, ".") { // eg. C.printf, C.strlen
|
||||||
|
name := pkgPath + "." + text[:idx]
|
||||||
|
p.link[name] = link[2:]
|
||||||
|
} else {
|
||||||
|
panic(line + ": no specified call convention. eg. //go:linkname Printf C.printf")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// func: pkg.name
|
||||||
|
// method: (pkg.T).name, (*pkg.T).name
|
||||||
|
func funcName(pkg *types.Package, fn *ssa.Function) string {
|
||||||
|
sig := fn.Signature
|
||||||
|
name := fn.Name()
|
||||||
|
if recv := sig.Recv(); recv != nil {
|
||||||
|
var tName string
|
||||||
|
t := recv.Type()
|
||||||
|
if tp, ok := t.(*types.Pointer); ok {
|
||||||
|
t, tName = tp.Elem(), "*"
|
||||||
|
}
|
||||||
|
tName += llssa.NameOf(t.(*types.Named))
|
||||||
|
return "(" + tName + ")." + name
|
||||||
|
}
|
||||||
|
ret := llssa.FullName(pkg, name)
|
||||||
|
if ret == "main.main" {
|
||||||
|
ret = "main"
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkCgo(fnName string) bool {
|
||||||
|
return len(fnName) > 4 && fnName[0] == '_' && fnName[2] == 'g' && fnName[3] == 'o' &&
|
||||||
|
(fnName[1] == 'C' || fnName[1] == 'c') &&
|
||||||
|
(fnName[4] == '_' || strings.HasPrefix(fnName[4:], "Check"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) funcName(pkg *types.Package, fn *ssa.Function, ignore bool) (string, bool) {
|
||||||
|
name := funcName(pkg, fn)
|
||||||
|
if ignore && ignoreName(name) || checkCgo(fn.Name()) {
|
||||||
|
return name, false
|
||||||
|
}
|
||||||
|
if v, ok := p.link[name]; ok {
|
||||||
|
return v, true
|
||||||
|
}
|
||||||
|
return name, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) funcOf(fn *ssa.Function) llssa.Function {
|
||||||
|
pkgTypes := p.ensureLoaded(fn.Pkg.Pkg)
|
||||||
|
pkg := p.pkg
|
||||||
|
name, _ := p.funcName(pkgTypes, fn, false)
|
||||||
|
if ret := pkg.FuncOf(name); ret != nil {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
return pkg.NewFunc(name, fn.Signature)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) varOf(v *ssa.Global) llssa.Global {
|
||||||
|
pkgTypes := p.ensureLoaded(v.Pkg.Pkg)
|
||||||
|
pkg := p.pkg
|
||||||
|
name := llssa.FullName(pkgTypes, v.Name())
|
||||||
|
if ret := pkg.VarOf(name); ret != nil {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
return pkg.NewVar(name, v.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) ensureLoaded(pkgTypes *types.Package) *types.Package {
|
||||||
|
if p.goTyps != pkgTypes {
|
||||||
|
if _, ok := p.loaded[pkgTypes]; !ok {
|
||||||
|
p.loaded[pkgTypes] = none{}
|
||||||
|
p.importPkg(pkgTypes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pkgTypes
|
||||||
|
}
|
||||||
14
cl/internal/libc/libc.go
Normal file
14
cl/internal/libc/libc.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package libc
|
||||||
|
|
||||||
|
import "C"
|
||||||
|
import _ "unsafe"
|
||||||
|
|
||||||
|
const (
|
||||||
|
LLGoPackage = true
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:linkname Printf C.printf
|
||||||
|
func Printf(format *int8, __llgo_va_list ...any)
|
||||||
|
|
||||||
|
//go:linkname Strlen C.strlen
|
||||||
|
func Strlen(str *int8) C.int
|
||||||
17
cl/internal/stdio/printf.go
Normal file
17
cl/internal/stdio/printf.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package stdio
|
||||||
|
|
||||||
|
import _ "unsafe"
|
||||||
|
|
||||||
|
const (
|
||||||
|
LLGoPackage = true
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:linkname Printf C.printf
|
||||||
|
func Printf(format *int8, __llgo_va_list ...any)
|
||||||
|
|
||||||
|
func Max(a, b int) int {
|
||||||
|
if a > b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2023 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 cl
|
|
||||||
|
|
||||||
/*
|
|
||||||
// Define unimplemented intrinsic functions.
|
|
||||||
//
|
|
||||||
// Some functions are either normally implemented in Go assembly (like
|
|
||||||
// sync/atomic functions) or intentionally left undefined to be implemented
|
|
||||||
// directly in the compiler (like runtime/volatile functions). Either way, look
|
|
||||||
// for these and implement them if this is the case.
|
|
||||||
func (b *builder) defineIntrinsicFunction() {
|
|
||||||
panic("todo")
|
|
||||||
}
|
|
||||||
|
|
||||||
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",
|
|
||||||
}
|
|
||||||
|
|
||||||
// defineMathOp defines a math function body as a call to a LLVM intrinsic,
|
|
||||||
// instead of the regular Go implementation. This allows LLVM to reason about
|
|
||||||
// the math operation and (depending on the architecture) allows it to lower the
|
|
||||||
// operation to very fast floating point instructions. If this is not possible,
|
|
||||||
// LLVM will emit a call to a libm function that implements the same operation.
|
|
||||||
//
|
|
||||||
// One example of an optimization that LLVM can do is to convert
|
|
||||||
// float32(math.Sqrt(float64(v))) to a 32-bit floating point operation, which is
|
|
||||||
// beneficial on architectures where 64-bit floating point operations are (much)
|
|
||||||
// more expensive than 32-bit ones.
|
|
||||||
func (b *builder) defineMathOp() {
|
|
||||||
panic("todo")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement most math/bits functions.
|
|
||||||
//
|
|
||||||
// This implements all the functions that operate on bits. It does not yet
|
|
||||||
// implement the arithmetic functions (like bits.Add), which also have LLVM
|
|
||||||
// intrinsics.
|
|
||||||
func (b *builder) defineMathBitsIntrinsic() bool {
|
|
||||||
panic("todo")
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2023 The GoPlus Authors (goplus.org). All rights reserved.
|
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -14,93 +14,32 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Package build implements the “llgo build” command.
|
// Package build implements the "llgo build" command.
|
||||||
package build
|
package build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"github.com/goplus/gop"
|
|
||||||
"github.com/goplus/gop/x/gopprojs"
|
|
||||||
"github.com/goplus/llgo"
|
|
||||||
"github.com/goplus/llgo/cmd/internal/base"
|
"github.com/goplus/llgo/cmd/internal/base"
|
||||||
"github.com/goplus/llgo/x/gocmd"
|
"github.com/goplus/llgo/internal/build"
|
||||||
)
|
)
|
||||||
|
|
||||||
// llgo build
|
// llgo build
|
||||||
var Cmd = &base.Command{
|
var Cmd = &base.Command{
|
||||||
UsageLine: "llgo build [flags] [packages]",
|
UsageLine: "llgo build [-o output] [build flags] [packages]",
|
||||||
Short: "Build Go files",
|
Short: "Compile packages and dependencies",
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
flagOutput = flag.String("o", "", "build output file")
|
|
||||||
_ = flag.Bool("v", false, "print verbose information")
|
|
||||||
flag = &Cmd.Flag
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Cmd.Run = runCmd
|
Cmd.Run = runCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCmd(cmd *base.Command, args []string) {
|
func runCmd(cmd *base.Command, args []string) {
|
||||||
err := flag.Parse(args)
|
conf := &build.Config{
|
||||||
if err != nil {
|
Mode: build.ModeBuild,
|
||||||
log.Panicln("parse input arguments failed:", err)
|
AppExt: build.DefaultAppExt(),
|
||||||
}
|
}
|
||||||
|
if len(args) >= 2 && args[0] == "-o" {
|
||||||
args = flag.Args()
|
conf.OutFile = args[1]
|
||||||
if len(args) == 0 {
|
args = args[2:]
|
||||||
args = []string{"."}
|
|
||||||
}
|
}
|
||||||
|
build.Do(args, conf)
|
||||||
proj, args, err := gopprojs.ParseOne(args...)
|
|
||||||
if err != nil {
|
|
||||||
log.Panicln(err)
|
|
||||||
}
|
}
|
||||||
if len(args) != 0 {
|
|
||||||
log.Panicln("too many arguments:", args)
|
|
||||||
}
|
|
||||||
|
|
||||||
conf := &llgo.Config{}
|
|
||||||
confCmd := &gocmd.BuildConfig{}
|
|
||||||
if *flagOutput != "" {
|
|
||||||
output, err := filepath.Abs(*flagOutput)
|
|
||||||
if err != nil {
|
|
||||||
log.Panicln(err)
|
|
||||||
}
|
|
||||||
confCmd.Output = output
|
|
||||||
}
|
|
||||||
build(proj, conf, confCmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
func build(proj gopprojs.Proj, conf *llgo.Config, build *gocmd.BuildConfig) {
|
|
||||||
var obj string
|
|
||||||
var err error
|
|
||||||
switch v := proj.(type) {
|
|
||||||
case *gopprojs.DirProj:
|
|
||||||
obj = v.Dir
|
|
||||||
err = llgo.BuildDir(obj, conf, build)
|
|
||||||
case *gopprojs.PkgPathProj:
|
|
||||||
obj = v.Path
|
|
||||||
err = llgo.BuildPkgPath("", obj, conf, build)
|
|
||||||
case *gopprojs.FilesProj:
|
|
||||||
err = llgo.BuildFiles(v.Files, conf, build)
|
|
||||||
default:
|
|
||||||
log.Panicln("`llgo build` doesn't support", reflect.TypeOf(v))
|
|
||||||
}
|
|
||||||
if gop.NotFound(err) {
|
|
||||||
fmt.Fprintf(os.Stderr, "llgo build %v: not found\n", obj)
|
|
||||||
} else if err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, err)
|
|
||||||
} else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|||||||
38
cmd/internal/clean/clean.go
Normal file
38
cmd/internal/clean/clean.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* 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 clean implements the "llgo clean" command.
|
||||||
|
package clean
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/goplus/llgo/cmd/internal/base"
|
||||||
|
"github.com/goplus/llgo/internal/build"
|
||||||
|
)
|
||||||
|
|
||||||
|
// llgo build
|
||||||
|
var Cmd = &base.Command{
|
||||||
|
UsageLine: "llgo clean [clean flags] [build flags] [packages]",
|
||||||
|
Short: "Remove object files and cached files",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Cmd.Run = runCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCmd(cmd *base.Command, args []string) {
|
||||||
|
conf := build.NewDefaultConf(0)
|
||||||
|
build.Clean(args, conf)
|
||||||
|
}
|
||||||
38
cmd/internal/install/install.go
Normal file
38
cmd/internal/install/install.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* 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 install implements the "llgo install" command.
|
||||||
|
package install
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/goplus/llgo/cmd/internal/base"
|
||||||
|
"github.com/goplus/llgo/internal/build"
|
||||||
|
)
|
||||||
|
|
||||||
|
// llgo install
|
||||||
|
var Cmd = &base.Command{
|
||||||
|
UsageLine: "llgo install [build flags] [packages]",
|
||||||
|
Short: "Compile and install packages and dependencies",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Cmd.Run = runCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCmd(cmd *base.Command, args []string) {
|
||||||
|
conf := build.NewDefaultConf(build.ModeInstall)
|
||||||
|
build.Do(args, conf)
|
||||||
|
}
|
||||||
75
cmd/internal/run/run.go
Normal file
75
cmd/internal/run/run.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* 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 run implements the "llgo run" command.
|
||||||
|
package run
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/cmd/internal/base"
|
||||||
|
"github.com/goplus/llgo/internal/build"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errNoProj = errors.New("llgo: no go files listed")
|
||||||
|
)
|
||||||
|
|
||||||
|
// llgo run
|
||||||
|
var Cmd = &base.Command{
|
||||||
|
UsageLine: "llgo run [build flags] package [arguments...]",
|
||||||
|
Short: "Compile and run Go program",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Cmd.Run = runCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCmd(cmd *base.Command, args []string) {
|
||||||
|
args, runArgs, err := parseRunArgs(args)
|
||||||
|
check(err)
|
||||||
|
conf := build.NewDefaultConf(build.ModeRun)
|
||||||
|
conf.RunArgs = runArgs
|
||||||
|
build.Do(args, conf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseRunArgs(args []string) ([]string, []string, error) {
|
||||||
|
n := build.SkipFlagArgs(args)
|
||||||
|
if n < 0 {
|
||||||
|
return nil, nil, errNoProj
|
||||||
|
}
|
||||||
|
|
||||||
|
arg := args[n]
|
||||||
|
if isGoFile(arg) {
|
||||||
|
n++
|
||||||
|
for n < len(args) && isGoFile(args[n]) {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
return args[:n], args[n:], nil
|
||||||
|
}
|
||||||
|
return args[:n+1], args[n+1:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isGoFile(fname string) bool {
|
||||||
|
return filepath.Ext(fname) == ".go"
|
||||||
|
}
|
||||||
|
|
||||||
|
func check(err error) {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,7 +26,10 @@ import (
|
|||||||
|
|
||||||
"github.com/goplus/llgo/cmd/internal/base"
|
"github.com/goplus/llgo/cmd/internal/base"
|
||||||
"github.com/goplus/llgo/cmd/internal/build"
|
"github.com/goplus/llgo/cmd/internal/build"
|
||||||
|
"github.com/goplus/llgo/cmd/internal/clean"
|
||||||
"github.com/goplus/llgo/cmd/internal/help"
|
"github.com/goplus/llgo/cmd/internal/help"
|
||||||
|
"github.com/goplus/llgo/cmd/internal/install"
|
||||||
|
"github.com/goplus/llgo/cmd/internal/run"
|
||||||
)
|
)
|
||||||
|
|
||||||
func mainUsage() {
|
func mainUsage() {
|
||||||
@@ -38,6 +41,9 @@ func init() {
|
|||||||
flag.Usage = mainUsage
|
flag.Usage = mainUsage
|
||||||
base.Llgo.Commands = []*base.Command{
|
base.Llgo.Commands = []*base.Command{
|
||||||
build.Cmd,
|
build.Cmd,
|
||||||
|
install.Cmd,
|
||||||
|
run.Cmd,
|
||||||
|
clean.Cmd,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
10
go.mod
10
go.mod
@@ -4,14 +4,14 @@ go 1.18
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/aykevl/go-wasm v0.0.1
|
github.com/aykevl/go-wasm v0.0.1
|
||||||
github.com/goplus/gop v1.2.6
|
github.com/goplus/gogen v1.15.2
|
||||||
github.com/goplus/llvm v0.7.1-0.20240420180312-6230a4ea7a47
|
github.com/goplus/llvm v0.7.2
|
||||||
|
github.com/goplus/mod v0.13.10
|
||||||
github.com/qiniu/x v1.13.10
|
github.com/qiniu/x v1.13.10
|
||||||
golang.org/x/tools v0.19.0
|
golang.org/x/tools v0.20.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/goplus/gogen v1.15.2 // indirect
|
|
||||||
github.com/goplus/mod v0.13.10 // indirect
|
|
||||||
golang.org/x/mod v0.17.0 // indirect
|
golang.org/x/mod v0.17.0 // indirect
|
||||||
|
golang.org/x/sync v0.7.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
17
go.sum
17
go.sum
@@ -2,12 +2,10 @@ github.com/aykevl/go-wasm v0.0.1 h1:lPxy8l48P39W7I0tLrtCrLfZBOUq9IWZ7odGdyJP2AM=
|
|||||||
github.com/aykevl/go-wasm v0.0.1/go.mod h1:b4nggwg3lEkNKOU4wzhtLKz2q2sLxSHFnc98aGt6z/Y=
|
github.com/aykevl/go-wasm v0.0.1/go.mod h1:b4nggwg3lEkNKOU4wzhtLKz2q2sLxSHFnc98aGt6z/Y=
|
||||||
github.com/goplus/gogen v1.15.2 h1:Q6XaSx/Zi5tWnjfAziYsQI6Jv6MgODRpFtOYqNkiiqM=
|
github.com/goplus/gogen v1.15.2 h1:Q6XaSx/Zi5tWnjfAziYsQI6Jv6MgODRpFtOYqNkiiqM=
|
||||||
github.com/goplus/gogen v1.15.2/go.mod h1:92qEzVgv7y8JEFICWG9GvYI5IzfEkxYdsA1DbmnTkqk=
|
github.com/goplus/gogen v1.15.2/go.mod h1:92qEzVgv7y8JEFICWG9GvYI5IzfEkxYdsA1DbmnTkqk=
|
||||||
github.com/goplus/gop v1.2.6 h1:kog3c5Js+8EopqmI4+CwueXsqibnBwYVt5q5N7juRVY=
|
github.com/goplus/llvm v0.7.1 h1:B12Fr/wc3pAsq5PLuac9u9IuKpLRuCufdVAeGDP/MRw=
|
||||||
github.com/goplus/gop v1.2.6/go.mod h1:uREWbR1MrFaviZ4Mbx4ZCcAYDoqzO0iv1Qo6Np0Xx4E=
|
github.com/goplus/llvm v0.7.1/go.mod h1:PeVK8GgzxwAYCiMiUAJb5wJR6xbhj989tu9oulKLLT4=
|
||||||
github.com/goplus/llvm v0.7.1-0.20240418160956-6233231cbcc9 h1:E/NBN5tDh6COcJmygdBb9RAJhE4uIHfT51VBlP3tglU=
|
github.com/goplus/llvm v0.7.2 h1:NL3LlwAmYVCGA6yV40AjOvMDKl2dbCqoYPtugmLQK+E=
|
||||||
github.com/goplus/llvm v0.7.1-0.20240418160956-6233231cbcc9/go.mod h1:PeVK8GgzxwAYCiMiUAJb5wJR6xbhj989tu9oulKLLT4=
|
github.com/goplus/llvm v0.7.2/go.mod h1:PeVK8GgzxwAYCiMiUAJb5wJR6xbhj989tu9oulKLLT4=
|
||||||
github.com/goplus/llvm v0.7.1-0.20240420180312-6230a4ea7a47 h1:B3nWTLOQh4+Yqt6NryE/cVQdo/+NLiT8AtD4YaeKScg=
|
|
||||||
github.com/goplus/llvm v0.7.1-0.20240420180312-6230a4ea7a47/go.mod h1:PeVK8GgzxwAYCiMiUAJb5wJR6xbhj989tu9oulKLLT4=
|
|
||||||
github.com/goplus/mod v0.13.10 h1:5Om6KOvo31daN7N30kWU1vC5zhsJPM+uPbcEN/FnlzE=
|
github.com/goplus/mod v0.13.10 h1:5Om6KOvo31daN7N30kWU1vC5zhsJPM+uPbcEN/FnlzE=
|
||||||
github.com/goplus/mod v0.13.10/go.mod h1:HDuPZgpWiaTp3PUolFgsiX+Q77cbUWB/mikVHfYND3c=
|
github.com/goplus/mod v0.13.10/go.mod h1:HDuPZgpWiaTp3PUolFgsiX+Q77cbUWB/mikVHfYND3c=
|
||||||
github.com/qiniu/x v1.13.10 h1:J4Z3XugYzAq85SlyAfqlKVrbf05glMbAOh+QncsDQpE=
|
github.com/qiniu/x v1.13.10 h1:J4Z3XugYzAq85SlyAfqlKVrbf05glMbAOh+QncsDQpE=
|
||||||
@@ -31,7 +29,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||||
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@@ -56,6 +55,6 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
|||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
|
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
|
||||||
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
|
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|||||||
636
internal/abi/llgo_autogen.ll
Normal file
636
internal/abi/llgo_autogen.ll
Normal file
@@ -0,0 +1,636 @@
|
|||||||
|
; ModuleID = 'github.com/goplus/llgo/internal/abi'
|
||||||
|
source_filename = "github.com/goplus/llgo/internal/abi"
|
||||||
|
|
||||||
|
%"github.com/goplus/llgo/internal/abi.ArrayType" = type { %"github.com/goplus/llgo/internal/abi.Type", ptr, ptr, i64 }
|
||||||
|
%"github.com/goplus/llgo/internal/abi.Type" = type { i64, i64, i32, i8, i8, i8, i8, ptr, ptr, i32, i32 }
|
||||||
|
%"github.com/goplus/llgo/internal/abi.ChanType" = type { %"github.com/goplus/llgo/internal/abi.Type", ptr, i64 }
|
||||||
|
%"github.com/goplus/llgo/internal/abi.FuncType" = type { %"github.com/goplus/llgo/internal/abi.Type", i16, i16 }
|
||||||
|
%"github.com/goplus/llgo/internal/abi.InterfaceType" = type { %"github.com/goplus/llgo/internal/abi.Type", %"github.com/goplus/llgo/internal/abi.Name", %"github.com/goplus/llgo/internal/runtime.Slice" }
|
||||||
|
%"github.com/goplus/llgo/internal/abi.Name" = type { ptr }
|
||||||
|
%"github.com/goplus/llgo/internal/runtime.Slice" = type { ptr, i64, i64 }
|
||||||
|
%"github.com/goplus/llgo/internal/abi.MapType" = type { %"github.com/goplus/llgo/internal/abi.Type", ptr, ptr, ptr, ptr, i8, i8, i16, i32 }
|
||||||
|
%"github.com/goplus/llgo/internal/abi.PtrType" = type { %"github.com/goplus/llgo/internal/abi.Type", ptr }
|
||||||
|
%"github.com/goplus/llgo/internal/abi.SliceType" = type { %"github.com/goplus/llgo/internal/abi.Type", ptr }
|
||||||
|
%"github.com/goplus/llgo/internal/abi.StructType" = type { %"github.com/goplus/llgo/internal/abi.Type", %"github.com/goplus/llgo/internal/abi.Name", %"github.com/goplus/llgo/internal/runtime.Slice" }
|
||||||
|
|
||||||
|
@"github.com/goplus/llgo/internal/abi.init$guard" = global ptr null
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.ArrayType).ArrayType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.ArrayType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).ArrayType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.ArrayType).Common"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.ArrayType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).Common"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.ArrayType).FuncType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.ArrayType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).FuncType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.ArrayType).InterfaceType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.ArrayType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).InterfaceType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"(*github.com/goplus/llgo/internal/abi.ArrayType).Kind"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.ArrayType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Kind"(ptr %1)
|
||||||
|
ret i64 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.ArrayType).MapType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.ArrayType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).MapType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.ArrayType).StructType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.ArrayType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).StructType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.ChanType).ArrayType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.ChanType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).ArrayType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.ChanType).Common"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.ChanType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).Common"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.ChanType).FuncType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.ChanType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).FuncType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.ChanType).InterfaceType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.ChanType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).InterfaceType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"(*github.com/goplus/llgo/internal/abi.ChanType).Kind"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.ChanType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Kind"(ptr %1)
|
||||||
|
ret i64 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"(*github.com/goplus/llgo/internal/abi.ChanType).Len"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.ChanType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Len"(ptr %1)
|
||||||
|
ret i64 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.ChanType).MapType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.ChanType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).MapType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.ChanType).StructType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.ChanType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).StructType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.FuncType).ArrayType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.FuncType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).ArrayType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.FuncType).Common"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.FuncType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).Common"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.FuncType).Elem"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.FuncType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).Elem"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.FuncType).FuncType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.FuncType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).FuncType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.FuncType).InterfaceType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.FuncType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).InterfaceType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"(*github.com/goplus/llgo/internal/abi.FuncType).Kind"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.FuncType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Kind"(ptr %1)
|
||||||
|
ret i64 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"(*github.com/goplus/llgo/internal/abi.FuncType).Len"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.FuncType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Len"(ptr %1)
|
||||||
|
ret i64 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.FuncType).MapType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.FuncType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).MapType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.FuncType).StructType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.FuncType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).StructType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.InterfaceType).ArrayType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).ArrayType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.InterfaceType).Common"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).Common"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.InterfaceType).Elem"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).Elem"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.InterfaceType).FuncType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).FuncType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.InterfaceType).InterfaceType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).InterfaceType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"(*github.com/goplus/llgo/internal/abi.InterfaceType).Kind"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Kind"(ptr %1)
|
||||||
|
ret i64 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"(*github.com/goplus/llgo/internal/abi.InterfaceType).Len"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Len"(ptr %1)
|
||||||
|
ret i64 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.InterfaceType).MapType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).MapType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.InterfaceType).StructType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).StructType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.MapType).ArrayType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.MapType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).ArrayType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.MapType).Common"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.MapType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).Common"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.MapType).FuncType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.MapType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).FuncType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.MapType).InterfaceType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.MapType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).InterfaceType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"(*github.com/goplus/llgo/internal/abi.MapType).Kind"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.MapType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Kind"(ptr %1)
|
||||||
|
ret i64 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"(*github.com/goplus/llgo/internal/abi.MapType).Len"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.MapType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Len"(ptr %1)
|
||||||
|
ret i64 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.MapType).MapType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.MapType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).MapType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.MapType).StructType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.MapType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).StructType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.PtrType).ArrayType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.PtrType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).ArrayType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.PtrType).Common"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.PtrType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).Common"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.PtrType).FuncType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.PtrType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).FuncType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.PtrType).InterfaceType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.PtrType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).InterfaceType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"(*github.com/goplus/llgo/internal/abi.PtrType).Kind"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.PtrType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Kind"(ptr %1)
|
||||||
|
ret i64 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"(*github.com/goplus/llgo/internal/abi.PtrType).Len"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.PtrType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Len"(ptr %1)
|
||||||
|
ret i64 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.PtrType).MapType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.PtrType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).MapType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.PtrType).StructType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.PtrType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).StructType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.SliceType).ArrayType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.SliceType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).ArrayType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.SliceType).Common"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.SliceType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).Common"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.SliceType).FuncType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.SliceType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).FuncType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.SliceType).InterfaceType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.SliceType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).InterfaceType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"(*github.com/goplus/llgo/internal/abi.SliceType).Kind"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.SliceType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Kind"(ptr %1)
|
||||||
|
ret i64 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"(*github.com/goplus/llgo/internal/abi.SliceType).Len"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.SliceType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Len"(ptr %1)
|
||||||
|
ret i64 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.SliceType).MapType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.SliceType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).MapType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.SliceType).StructType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.SliceType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).StructType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.StructType).ArrayType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.StructType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).ArrayType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.StructType).Common"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.StructType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).Common"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.StructType).Elem"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.StructType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).Elem"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.StructType).FuncType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.StructType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).FuncType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.StructType).InterfaceType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.StructType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).InterfaceType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"(*github.com/goplus/llgo/internal/abi.StructType).Kind"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.StructType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Kind"(ptr %1)
|
||||||
|
ret i64 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"(*github.com/goplus/llgo/internal/abi.StructType).Len"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.StructType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Len"(ptr %1)
|
||||||
|
ret i64 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.StructType).MapType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.StructType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).MapType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.StructType).StructType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.StructType", ptr %0, i32 0, i32 0
|
||||||
|
%2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).StructType"(ptr %1)
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.Type).ArrayType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Kind"(ptr %0)
|
||||||
|
%2 = icmp ne i64 %1, 17
|
||||||
|
br i1 %2, label %_llgo_1, label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
ret ptr null
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_0
|
||||||
|
ret ptr %0
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.Type).Common"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
ret ptr %0
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.Type).Elem"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Kind"(ptr %0)
|
||||||
|
%2 = icmp eq i64 %1, 17
|
||||||
|
br i1 %2, label %_llgo_1, label %_llgo_3
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.ArrayType", ptr %0, i32 0, i32 1
|
||||||
|
%4 = load ptr, ptr %3, align 8
|
||||||
|
ret ptr %4
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_3
|
||||||
|
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.ChanType", ptr %0, i32 0, i32 1
|
||||||
|
%6 = load ptr, ptr %5, align 8
|
||||||
|
ret ptr %6
|
||||||
|
|
||||||
|
_llgo_3: ; preds = %_llgo_0
|
||||||
|
%7 = icmp eq i64 %1, 18
|
||||||
|
br i1 %7, label %_llgo_2, label %_llgo_5
|
||||||
|
|
||||||
|
_llgo_4: ; preds = %_llgo_5
|
||||||
|
%8 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.MapType", ptr %0, i32 0, i32 2
|
||||||
|
%9 = load ptr, ptr %8, align 8
|
||||||
|
ret ptr %9
|
||||||
|
|
||||||
|
_llgo_5: ; preds = %_llgo_3
|
||||||
|
%10 = icmp eq i64 %1, 21
|
||||||
|
br i1 %10, label %_llgo_4, label %_llgo_7
|
||||||
|
|
||||||
|
_llgo_6: ; preds = %_llgo_7
|
||||||
|
%11 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.PtrType", ptr %0, i32 0, i32 1
|
||||||
|
%12 = load ptr, ptr %11, align 8
|
||||||
|
ret ptr %12
|
||||||
|
|
||||||
|
_llgo_7: ; preds = %_llgo_5
|
||||||
|
%13 = icmp eq i64 %1, 22
|
||||||
|
br i1 %13, label %_llgo_6, label %_llgo_9
|
||||||
|
|
||||||
|
_llgo_8: ; preds = %_llgo_9
|
||||||
|
%14 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.SliceType", ptr %0, i32 0, i32 1
|
||||||
|
%15 = load ptr, ptr %14, align 8
|
||||||
|
ret ptr %15
|
||||||
|
|
||||||
|
_llgo_9: ; preds = %_llgo_7
|
||||||
|
%16 = icmp eq i64 %1, 23
|
||||||
|
br i1 %16, label %_llgo_8, label %_llgo_10
|
||||||
|
|
||||||
|
_llgo_10: ; preds = %_llgo_9
|
||||||
|
ret ptr null
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.Type).FuncType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Kind"(ptr %0)
|
||||||
|
%2 = icmp ne i64 %1, 19
|
||||||
|
br i1 %2, label %_llgo_1, label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
ret ptr null
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_0
|
||||||
|
ret ptr %0
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.Type).InterfaceType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Kind"(ptr %0)
|
||||||
|
%2 = icmp ne i64 %1, 20
|
||||||
|
br i1 %2, label %_llgo_1, label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
ret ptr null
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_0
|
||||||
|
ret ptr %0
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"(*github.com/goplus/llgo/internal/abi.Type).Kind"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.Type", ptr %0, i32 0, i32 6
|
||||||
|
%2 = load i8, ptr %1, align 1
|
||||||
|
%3 = and i8 %2, 31
|
||||||
|
%4 = sext i8 %3 to i64
|
||||||
|
ret i64 %4
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"(*github.com/goplus/llgo/internal/abi.Type).Len"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Kind"(ptr %0)
|
||||||
|
%2 = icmp eq i64 %1, 17
|
||||||
|
br i1 %2, label %_llgo_1, label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.ArrayType", ptr %0, i32 0, i32 3
|
||||||
|
%4 = load i64, ptr %3, align 4
|
||||||
|
ret i64 %4
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_0
|
||||||
|
ret i64 0
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.Type).MapType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Kind"(ptr %0)
|
||||||
|
%2 = icmp ne i64 %1, 21
|
||||||
|
br i1 %2, label %_llgo_1, label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
ret ptr null
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_0
|
||||||
|
ret ptr %0
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"(*github.com/goplus/llgo/internal/abi.Type).StructType"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Kind"(ptr %0)
|
||||||
|
%2 = icmp ne i64 %1, 25
|
||||||
|
br i1 %2, label %_llgo_1, label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
ret ptr null
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_0
|
||||||
|
ret ptr %0
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @"github.com/goplus/llgo/internal/abi.init"() {
|
||||||
|
_llgo_0:
|
||||||
|
%0 = load i1, ptr @"github.com/goplus/llgo/internal/abi.init$guard", align 1
|
||||||
|
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
store i1 true, ptr @"github.com/goplus/llgo/internal/abi.init$guard", align 1
|
||||||
|
br label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
332
internal/abi/type.go
Normal file
332
internal/abi/type.go
Normal file
@@ -0,0 +1,332 @@
|
|||||||
|
/*
|
||||||
|
* 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 abi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Type is the runtime representation of a Go type.
|
||||||
|
//
|
||||||
|
// Type is also referenced implicitly
|
||||||
|
// (in the form of expressions involving constants and arch.PtrSize)
|
||||||
|
// in cmd/compile/internal/reflectdata/reflect.go
|
||||||
|
// and cmd/link/internal/ld/decodesym.go
|
||||||
|
// (e.g. data[2*arch.PtrSize+4] references the TFlag field)
|
||||||
|
// unsafe.OffsetOf(Type{}.TFlag) cannot be used directly in those
|
||||||
|
// places because it varies with cross compilation and experiments.
|
||||||
|
type Type struct {
|
||||||
|
Size_ uintptr
|
||||||
|
PtrBytes uintptr // number of (prefix) bytes in the type that can contain pointers
|
||||||
|
Hash uint32 // hash of type; avoids computation in hash tables
|
||||||
|
TFlag TFlag // extra type information flags
|
||||||
|
Align_ uint8 // alignment of variable with this type
|
||||||
|
FieldAlign_ uint8 // alignment of struct field with this type
|
||||||
|
Kind_ uint8 // enumeration for C
|
||||||
|
// function for comparing objects of this type
|
||||||
|
// (ptr to object A, ptr to object B) -> ==?
|
||||||
|
Equal func(unsafe.Pointer, unsafe.Pointer) bool
|
||||||
|
// GCData stores the GC type data for the garbage collector.
|
||||||
|
// If the KindGCProg bit is set in kind, GCData is a GC program.
|
||||||
|
// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
|
||||||
|
GCData *byte
|
||||||
|
Str NameOff // string form
|
||||||
|
PtrToThis TypeOff // type for pointer to this type, may be zero
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Type) Kind() Kind { return Kind(t.Kind_ & KindMask) }
|
||||||
|
|
||||||
|
// A Kind represents the specific kind of type that a Type represents.
|
||||||
|
// The zero Kind is not a valid kind.
|
||||||
|
type Kind uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
Invalid Kind = iota
|
||||||
|
Bool
|
||||||
|
Int
|
||||||
|
Int8
|
||||||
|
Int16
|
||||||
|
Int32
|
||||||
|
Int64
|
||||||
|
Uint
|
||||||
|
Uint8
|
||||||
|
Uint16
|
||||||
|
Uint32
|
||||||
|
Uint64
|
||||||
|
Uintptr
|
||||||
|
Float32
|
||||||
|
Float64
|
||||||
|
Complex64
|
||||||
|
Complex128
|
||||||
|
Array
|
||||||
|
Chan
|
||||||
|
Func
|
||||||
|
Interface
|
||||||
|
Map
|
||||||
|
Pointer
|
||||||
|
Slice
|
||||||
|
String
|
||||||
|
Struct
|
||||||
|
UnsafePointer
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TODO (khr, drchase) why aren't these in TFlag? Investigate, fix if possible.
|
||||||
|
KindDirectIface = 1 << 5
|
||||||
|
KindGCProg = 1 << 6 // Type.gc points to GC program
|
||||||
|
KindMask = (1 << 5) - 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// TFlag is used by a Type to signal what extra type information is
|
||||||
|
// available in the memory directly following the Type value.
|
||||||
|
type TFlag uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TFlagUncommon means that there is a data with a type, UncommonType,
|
||||||
|
// just beyond the shared-per-type common data. That is, the data
|
||||||
|
// for struct types will store their UncommonType at one offset, the
|
||||||
|
// data for interface types will store their UncommonType at a different
|
||||||
|
// offset. UncommonType is always accessed via a pointer that is computed
|
||||||
|
// using trust-us-we-are-the-implementors pointer arithmetic.
|
||||||
|
//
|
||||||
|
// For example, if t.Kind() == Struct and t.tflag&TFlagUncommon != 0,
|
||||||
|
// then t has UncommonType data and it can be accessed as:
|
||||||
|
//
|
||||||
|
// type structTypeUncommon struct {
|
||||||
|
// structType
|
||||||
|
// u UncommonType
|
||||||
|
// }
|
||||||
|
// u := &(*structTypeUncommon)(unsafe.Pointer(t)).u
|
||||||
|
TFlagUncommon TFlag = 1 << 0
|
||||||
|
|
||||||
|
// TFlagExtraStar means the name in the str field has an
|
||||||
|
// extraneous '*' prefix. This is because for most types T in
|
||||||
|
// a program, the type *T also exists and reusing the str data
|
||||||
|
// saves binary size.
|
||||||
|
TFlagExtraStar TFlag = 1 << 1
|
||||||
|
|
||||||
|
// TFlagNamed means the type has a name.
|
||||||
|
TFlagNamed TFlag = 1 << 2
|
||||||
|
|
||||||
|
// TFlagRegularMemory means that equal and hash functions can treat
|
||||||
|
// this type as a single region of t.size bytes.
|
||||||
|
TFlagRegularMemory TFlag = 1 << 3
|
||||||
|
)
|
||||||
|
|
||||||
|
// NameOff is the offset to a name from moduledata.types. See resolveNameOff in runtime.
|
||||||
|
type NameOff int32
|
||||||
|
|
||||||
|
// TypeOff is the offset to a type from moduledata.types. See resolveTypeOff in runtime.
|
||||||
|
type TypeOff int32
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// ArrayType represents a fixed array type.
|
||||||
|
type ArrayType struct {
|
||||||
|
Type
|
||||||
|
Elem *Type // array element type
|
||||||
|
Slice *Type // slice type
|
||||||
|
Len uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
type SliceType struct {
|
||||||
|
Type
|
||||||
|
Elem *Type // slice element type
|
||||||
|
}
|
||||||
|
|
||||||
|
type MapType struct {
|
||||||
|
Type
|
||||||
|
Key *Type
|
||||||
|
Elem *Type
|
||||||
|
Bucket *Type // internal type representing a hash bucket
|
||||||
|
// function for hashing keys (ptr to key, seed) -> hash
|
||||||
|
Hasher func(unsafe.Pointer, uintptr) uintptr
|
||||||
|
KeySize uint8 // size of key slot
|
||||||
|
ValueSize uint8 // size of elem slot
|
||||||
|
BucketSize uint16 // size of bucket
|
||||||
|
Flags uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type PtrType struct {
|
||||||
|
Type
|
||||||
|
Elem *Type // pointer element (pointed at) type
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChanDir int
|
||||||
|
|
||||||
|
const (
|
||||||
|
RecvDir ChanDir = 1 << iota // <-chan
|
||||||
|
SendDir // chan<-
|
||||||
|
BothDir = RecvDir | SendDir // chan
|
||||||
|
InvalidDir ChanDir = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
// ChanType represents a channel type
|
||||||
|
type ChanType struct {
|
||||||
|
Type
|
||||||
|
Elem *Type
|
||||||
|
Dir ChanDir
|
||||||
|
}
|
||||||
|
|
||||||
|
// funcType represents a function type.
|
||||||
|
//
|
||||||
|
// A *Type for each in and out parameter is stored in an array that
|
||||||
|
// directly follows the funcType (and possibly its uncommonType). So
|
||||||
|
// a function type with one method, one input, and one output is:
|
||||||
|
//
|
||||||
|
// struct {
|
||||||
|
// funcType
|
||||||
|
// uncommonType
|
||||||
|
// [2]*rtype // [0] is in, [1] is out
|
||||||
|
// }
|
||||||
|
type FuncType struct {
|
||||||
|
Type
|
||||||
|
InCount uint16
|
||||||
|
OutCount uint16 // top bit is set if last input parameter is ...
|
||||||
|
}
|
||||||
|
|
||||||
|
type StructField struct {
|
||||||
|
Name Name // name is always non-empty
|
||||||
|
Typ *Type // type of field
|
||||||
|
Offset uintptr // byte offset of field
|
||||||
|
}
|
||||||
|
|
||||||
|
type StructType struct {
|
||||||
|
Type
|
||||||
|
PkgPath Name
|
||||||
|
Fields []StructField
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name is an encoded type Name with optional extra data.
|
||||||
|
//
|
||||||
|
// The first byte is a bit field containing:
|
||||||
|
//
|
||||||
|
// 1<<0 the name is exported
|
||||||
|
// 1<<1 tag data follows the name
|
||||||
|
// 1<<2 pkgPath nameOff follows the name and tag
|
||||||
|
// 1<<3 the name is of an embedded (a.k.a. anonymous) field
|
||||||
|
//
|
||||||
|
// Following that, there is a varint-encoded length of the name,
|
||||||
|
// followed by the name itself.
|
||||||
|
//
|
||||||
|
// If tag data is present, it also has a varint-encoded length
|
||||||
|
// followed by the tag itself.
|
||||||
|
//
|
||||||
|
// If the import path follows, then 4 bytes at the end of
|
||||||
|
// the data form a nameOff. The import path is only set for concrete
|
||||||
|
// methods that are defined in a different package than their type.
|
||||||
|
//
|
||||||
|
// If a name starts with "*", then the exported bit represents
|
||||||
|
// whether the pointed to type is exported.
|
||||||
|
//
|
||||||
|
// Note: this encoding must match here and in:
|
||||||
|
// cmd/compile/internal/reflectdata/reflect.go
|
||||||
|
// cmd/link/internal/ld/decodesym.go
|
||||||
|
|
||||||
|
type Name struct {
|
||||||
|
Bytes *byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type InterfaceType struct {
|
||||||
|
Type
|
||||||
|
PkgPath Name // import path
|
||||||
|
Methods []Imethod // sorted by hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// Imethod represents a method on an interface type
|
||||||
|
type Imethod struct {
|
||||||
|
Name NameOff // name of method
|
||||||
|
Typ TypeOff // .(*FuncType) underneath
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Type) Common() *Type {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the length of t if t is an array type, otherwise 0
|
||||||
|
func (t *Type) Len() int {
|
||||||
|
if t.Kind() == Array {
|
||||||
|
return int((*ArrayType)(unsafe.Pointer(t)).Len)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Elem returns the element type for t if t is an array, channel, map, pointer, or slice, otherwise nil.
|
||||||
|
func (t *Type) Elem() *Type {
|
||||||
|
switch t.Kind() {
|
||||||
|
case Array:
|
||||||
|
tt := (*ArrayType)(unsafe.Pointer(t))
|
||||||
|
return tt.Elem
|
||||||
|
case Chan:
|
||||||
|
tt := (*ChanType)(unsafe.Pointer(t))
|
||||||
|
return tt.Elem
|
||||||
|
case Map:
|
||||||
|
tt := (*MapType)(unsafe.Pointer(t))
|
||||||
|
return tt.Elem
|
||||||
|
case Pointer:
|
||||||
|
tt := (*PtrType)(unsafe.Pointer(t))
|
||||||
|
return tt.Elem
|
||||||
|
case Slice:
|
||||||
|
tt := (*SliceType)(unsafe.Pointer(t))
|
||||||
|
return tt.Elem
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StructType returns t cast to a *StructType, or nil if its tag does not match.
|
||||||
|
func (t *Type) StructType() *StructType {
|
||||||
|
if t.Kind() != Struct {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return (*StructType)(unsafe.Pointer(t))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapType returns t cast to a *MapType, or nil if its tag does not match.
|
||||||
|
func (t *Type) MapType() *MapType {
|
||||||
|
if t.Kind() != Map {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return (*MapType)(unsafe.Pointer(t))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArrayType returns t cast to a *ArrayType, or nil if its tag does not match.
|
||||||
|
func (t *Type) ArrayType() *ArrayType {
|
||||||
|
if t.Kind() != Array {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return (*ArrayType)(unsafe.Pointer(t))
|
||||||
|
}
|
||||||
|
|
||||||
|
// FuncType returns t cast to a *FuncType, or nil if its tag does not match.
|
||||||
|
func (t *Type) FuncType() *FuncType {
|
||||||
|
if t.Kind() != Func {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return (*FuncType)(unsafe.Pointer(t))
|
||||||
|
}
|
||||||
|
|
||||||
|
// InterfaceType returns t cast to a *InterfaceType, or nil if its tag does not match.
|
||||||
|
func (t *Type) InterfaceType() *InterfaceType {
|
||||||
|
if t.Kind() != Interface {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return (*InterfaceType)(unsafe.Pointer(t))
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
358
internal/build/build.go
Normal file
358
internal/build/build.go
Normal file
@@ -0,0 +1,358 @@
|
|||||||
|
/*
|
||||||
|
* 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 build
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/packages"
|
||||||
|
"golang.org/x/tools/go/ssa"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/cl"
|
||||||
|
"github.com/goplus/llgo/x/clang"
|
||||||
|
|
||||||
|
llssa "github.com/goplus/llgo/ssa"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Mode int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ModeBuild Mode = iota
|
||||||
|
ModeInstall
|
||||||
|
ModeRun
|
||||||
|
)
|
||||||
|
|
||||||
|
func needLLFile(mode Mode) bool {
|
||||||
|
return mode != ModeBuild
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
BinPath string
|
||||||
|
AppExt string // ".exe" on Windows, empty on Unix
|
||||||
|
OutFile string // only valid for ModeBuild when len(pkgs) == 1
|
||||||
|
RunArgs []string // only valid for ModeRun
|
||||||
|
Mode Mode
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultConf(mode Mode) *Config {
|
||||||
|
bin := os.Getenv("GOBIN")
|
||||||
|
if bin == "" {
|
||||||
|
bin = filepath.Join(runtime.GOROOT(), "bin")
|
||||||
|
}
|
||||||
|
conf := &Config{
|
||||||
|
BinPath: bin,
|
||||||
|
Mode: mode,
|
||||||
|
AppExt: DefaultAppExt(),
|
||||||
|
}
|
||||||
|
return conf
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultAppExt() string {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
return ".exe"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const (
|
||||||
|
loadFiles = packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles
|
||||||
|
loadImports = loadFiles | packages.NeedImports
|
||||||
|
loadTypes = loadImports | packages.NeedTypes | packages.NeedTypesSizes
|
||||||
|
loadSyntax = loadTypes | packages.NeedSyntax | packages.NeedTypesInfo
|
||||||
|
)
|
||||||
|
|
||||||
|
func Do(args []string, conf *Config) {
|
||||||
|
flags, patterns, verbose := ParseArgs(args, buildFlags)
|
||||||
|
cfg := &packages.Config{
|
||||||
|
Mode: loadSyntax | packages.NeedDeps | packages.NeedModule | packages.NeedExportFile,
|
||||||
|
BuildFlags: flags,
|
||||||
|
}
|
||||||
|
|
||||||
|
if patterns == nil {
|
||||||
|
patterns = []string{"."}
|
||||||
|
}
|
||||||
|
initial, err := packages.Load(cfg, patterns...)
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
mode := conf.Mode
|
||||||
|
if len(initial) == 1 && len(initial[0].CompiledGoFiles) > 0 {
|
||||||
|
if mode == ModeBuild {
|
||||||
|
mode = ModeInstall
|
||||||
|
}
|
||||||
|
} else if mode == ModeRun {
|
||||||
|
if len(initial) > 1 {
|
||||||
|
fmt.Fprintln(os.Stderr, "cannot run multiple packages")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintln(os.Stderr, "no Go files in matched packages")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
llssa.Initialize(llssa.InitAll)
|
||||||
|
if verbose {
|
||||||
|
llssa.SetDebug(llssa.DbgFlagAll)
|
||||||
|
cl.SetDebug(cl.DbgFlagAll)
|
||||||
|
}
|
||||||
|
|
||||||
|
var rt []*packages.Package
|
||||||
|
prog := llssa.NewProgram(nil)
|
||||||
|
prog.SetRuntime(func() *types.Package {
|
||||||
|
rt, err = packages.Load(cfg, llssa.PkgRuntime)
|
||||||
|
check(err)
|
||||||
|
return rt[0].Types
|
||||||
|
})
|
||||||
|
|
||||||
|
buildAllPkgs(prog, initial, mode, verbose)
|
||||||
|
|
||||||
|
var runtimeFiles []string
|
||||||
|
if rt != nil {
|
||||||
|
runtimeFiles = allLinkFiles(rt)
|
||||||
|
}
|
||||||
|
if mode != ModeBuild {
|
||||||
|
nErr := 0
|
||||||
|
for _, pkg := range initial {
|
||||||
|
if pkg.Name == "main" {
|
||||||
|
nErr += linkMainPkg(pkg, runtimeFiles, conf, mode, verbose)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if nErr > 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "%d errors occurred\n", nErr)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setNeedRuntime(pkg *packages.Package) {
|
||||||
|
pkg.ID = "" // just use pkg.Module to mark it needs runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNeedRuntime(pkg *packages.Package) bool {
|
||||||
|
return pkg.ID == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildAllPkgs(prog llssa.Program, initial []*packages.Package, mode Mode, verbose bool) {
|
||||||
|
// Create SSA-form program representation.
|
||||||
|
ssaProg, pkgs, errPkgs := allPkgs(initial, ssa.SanityCheckFunctions)
|
||||||
|
ssaProg.Build()
|
||||||
|
for _, errPkg := range errPkgs {
|
||||||
|
fmt.Fprintln(os.Stderr, "cannot build SSA for package", errPkg)
|
||||||
|
}
|
||||||
|
for _, pkg := range pkgs {
|
||||||
|
buildPkg(prog, pkg, mode, verbose)
|
||||||
|
if prog.NeedRuntime() {
|
||||||
|
setNeedRuntime(pkg.Package)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func linkMainPkg(pkg *packages.Package, runtimeFiles []string, conf *Config, mode Mode, verbose bool) (nErr int) {
|
||||||
|
pkgPath := pkg.PkgPath
|
||||||
|
name := path.Base(pkgPath)
|
||||||
|
app := conf.OutFile
|
||||||
|
if app == "" {
|
||||||
|
app = filepath.Join(conf.BinPath, name+conf.AppExt)
|
||||||
|
}
|
||||||
|
const N = 3
|
||||||
|
args := make([]string, N, len(pkg.Imports)+len(runtimeFiles)+(N+1))
|
||||||
|
args[0] = "-o"
|
||||||
|
args[1] = app
|
||||||
|
args[2] = "-Wno-override-module"
|
||||||
|
needRuntime := false
|
||||||
|
packages.Visit([]*packages.Package{pkg}, nil, func(p *packages.Package) {
|
||||||
|
if p.PkgPath != "unsafe" { // TODO(xsw): maybe can remove this special case
|
||||||
|
args = append(args, p.ExportFile+".ll")
|
||||||
|
if !needRuntime {
|
||||||
|
needRuntime = isNeedRuntime(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if needRuntime && runtimeFiles != nil {
|
||||||
|
args = append(args, runtimeFiles...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if verbose || mode != ModeRun {
|
||||||
|
fmt.Fprintln(os.Stderr, "#", pkgPath)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
nErr = 1
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// TODO(xsw): show work
|
||||||
|
// fmt.Fprintln(os.Stderr, "clang", args)
|
||||||
|
err := clang.New("").Exec(args...)
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
if mode == ModeRun {
|
||||||
|
cmd := exec.Command(app, conf.RunArgs...)
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Run()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildPkg(prog llssa.Program, aPkg aPackage, mode Mode, verbose bool) {
|
||||||
|
pkg := aPkg.Package
|
||||||
|
pkgPath := pkg.PkgPath
|
||||||
|
if verbose {
|
||||||
|
fmt.Fprintln(os.Stderr, pkgPath)
|
||||||
|
}
|
||||||
|
if pkgPath == "unsafe" { // TODO(xsw): maybe can remove this special case
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ret, err := cl.NewPackage(prog, aPkg.SSA, pkg.Syntax)
|
||||||
|
check(err)
|
||||||
|
if needLLFile(mode) {
|
||||||
|
file := pkg.ExportFile + ".ll"
|
||||||
|
os.WriteFile(file, []byte(ret.String()), 0644)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type aPackage struct {
|
||||||
|
*packages.Package
|
||||||
|
SSA *ssa.Package
|
||||||
|
}
|
||||||
|
|
||||||
|
func allPkgs(initial []*packages.Package, mode ssa.BuilderMode) (prog *ssa.Program, all []aPackage, errs []*packages.Package) {
|
||||||
|
var fset *token.FileSet
|
||||||
|
if len(initial) > 0 {
|
||||||
|
fset = initial[0].Fset
|
||||||
|
}
|
||||||
|
|
||||||
|
prog = ssa.NewProgram(fset, mode)
|
||||||
|
packages.Visit(initial, nil, func(p *packages.Package) {
|
||||||
|
if p.Types != nil && !p.IllTyped {
|
||||||
|
ssaPkg := prog.CreatePackage(p.Types, p.Syntax, p.TypesInfo, true)
|
||||||
|
all = append(all, aPackage{p, ssaPkg})
|
||||||
|
} else {
|
||||||
|
errs = append(errs, p)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// TODO(xsw): complete build flags
|
||||||
|
buildFlags = map[string]bool{
|
||||||
|
"-C": true, // -C dir: Change to dir before running the command
|
||||||
|
"-a": false, // -a: force rebuilding of packages that are already up-to-date
|
||||||
|
"-n": false, // -n: print the commands but do not run them
|
||||||
|
"-p": true, // -p n: the number of programs to run in parallel
|
||||||
|
"-race": false, // -race: enable data race detection
|
||||||
|
"-cover": false, // -cover: enable coverage analysis
|
||||||
|
"-covermode": true, // -covermode mode: set the mode for coverage analysis
|
||||||
|
"-v": false, // -v: print the names of packages as they are compiled
|
||||||
|
"-work": false, // -work: print the name of the temporary work directory and do not delete it when exiting
|
||||||
|
"-x": false, // -x: print the commands
|
||||||
|
"-tags": true, // -tags 'tag,list': a space-separated list of build tags to consider satisfied during the build
|
||||||
|
"-pkgdir": true, // -pkgdir dir: install and load all packages from dir instead of the usual locations
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func ParseArgs(args []string, swflags map[string]bool) (flags, patterns []string, verbose bool) {
|
||||||
|
n := len(args)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
arg := args[i]
|
||||||
|
if strings.HasPrefix(arg, "-") {
|
||||||
|
checkFlag(arg, &i, &verbose, swflags)
|
||||||
|
} else {
|
||||||
|
flags, patterns = args[:i], args[i:]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flags = args
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func SkipFlagArgs(args []string) int {
|
||||||
|
n := len(args)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
arg := args[i]
|
||||||
|
if strings.HasPrefix(arg, "-") {
|
||||||
|
checkFlag(arg, &i, nil, buildFlags)
|
||||||
|
} else {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkFlag(arg string, i *int, verbose *bool, swflags map[string]bool) {
|
||||||
|
if hasarg, ok := swflags[arg]; ok {
|
||||||
|
if hasarg {
|
||||||
|
*i++
|
||||||
|
} else if verbose != nil && arg == "-v" {
|
||||||
|
*verbose = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic("unknown flag: " + arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func allLinkFiles(rt []*packages.Package) (outFiles []string) {
|
||||||
|
outFiles = make([]string, 0, len(rt))
|
||||||
|
root := rootLLGo(rt[0])
|
||||||
|
packages.Visit(rt, nil, func(p *packages.Package) {
|
||||||
|
if isPkgInLLGo(p.PkgPath) {
|
||||||
|
outFile := filepath.Join(root+p.PkgPath[len(llgoModPath):], "llgo_autogen.ll")
|
||||||
|
outFiles = append(outFiles, outFile)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(xsw): llgo root dir
|
||||||
|
func rootLLGo(runtime *packages.Package) string {
|
||||||
|
return runtime.Module.Dir
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
llgoModPath = "github.com/goplus/llgo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func isPkgInLLGo(pkgPath string) bool {
|
||||||
|
return isPkgInMod(pkgPath, llgoModPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPkgInMod(pkgPath, modPath string) bool {
|
||||||
|
if strings.HasPrefix(pkgPath, modPath) {
|
||||||
|
suffix := pkgPath[len(modPath):]
|
||||||
|
return suffix == "" || suffix[0] == '/'
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func check(err error) {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
85
internal/build/clean.go
Normal file
85
internal/build/clean.go
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* 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 build
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/packages"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// TODO(xsw): complete clean flags
|
||||||
|
cleanFlags = map[string]bool{
|
||||||
|
"-v": false, // -v: print the paths of packages as they are clean
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func Clean(args []string, conf *Config) {
|
||||||
|
flags, patterns, verbose := ParseArgs(args, cleanFlags)
|
||||||
|
cfg := &packages.Config{
|
||||||
|
Mode: loadSyntax | packages.NeedExportFile,
|
||||||
|
BuildFlags: flags,
|
||||||
|
}
|
||||||
|
|
||||||
|
if patterns == nil {
|
||||||
|
patterns = []string{"."}
|
||||||
|
}
|
||||||
|
initial, err := packages.Load(cfg, patterns...)
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
cleanPkgs(initial, verbose)
|
||||||
|
|
||||||
|
for _, pkg := range initial {
|
||||||
|
if pkg.Name == "main" {
|
||||||
|
cleanMainPkg(pkg, conf, verbose)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanMainPkg(pkg *packages.Package, conf *Config, verbose bool) {
|
||||||
|
pkgPath := pkg.PkgPath
|
||||||
|
name := path.Base(pkgPath)
|
||||||
|
fname := name + conf.AppExt
|
||||||
|
app := filepath.Join(conf.BinPath, fname)
|
||||||
|
removeFile(app, verbose)
|
||||||
|
if len(pkg.CompiledGoFiles) > 0 {
|
||||||
|
dir := filepath.Dir(pkg.CompiledGoFiles[0])
|
||||||
|
buildApp := filepath.Join(dir, fname)
|
||||||
|
removeFile(buildApp, verbose)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanPkgs(initial []*packages.Package, verbose bool) {
|
||||||
|
packages.Visit(initial, nil, func(p *packages.Package) {
|
||||||
|
file := p.ExportFile + ".ll"
|
||||||
|
removeFile(file, verbose)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeFile(file string, verbose bool) {
|
||||||
|
if _, err := os.Stat(file); os.IsNotExist(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if verbose {
|
||||||
|
fmt.Fprintln(os.Stderr, "Remove", file)
|
||||||
|
}
|
||||||
|
os.Remove(file)
|
||||||
|
}
|
||||||
@@ -18,13 +18,14 @@ package llgen
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/importer"
|
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/goplus/gogen/packages"
|
||||||
"github.com/goplus/llgo/cl"
|
"github.com/goplus/llgo/cl"
|
||||||
|
"github.com/goplus/llgo/internal/mod"
|
||||||
"golang.org/x/tools/go/ssa"
|
"golang.org/x/tools/go/ssa"
|
||||||
"golang.org/x/tools/go/ssa/ssautil"
|
"golang.org/x/tools/go/ssa/ssautil"
|
||||||
|
|
||||||
@@ -37,28 +38,38 @@ func Init() {
|
|||||||
cl.SetDebug(cl.DbgFlagAll)
|
cl.SetDebug(cl.DbgFlagAll)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Do(inFile, outFile string) {
|
func PkgPath(dir string) string {
|
||||||
ret := Gen(inFile, nil)
|
_, pkgPath, err := mod.Load(dir)
|
||||||
|
check(err)
|
||||||
|
return pkgPath
|
||||||
|
}
|
||||||
|
|
||||||
|
func Do(pkgPath, inFile, outFile string) {
|
||||||
|
ret := Gen(pkgPath, inFile, nil)
|
||||||
err := os.WriteFile(outFile, []byte(ret), 0644)
|
err := os.WriteFile(outFile, []byte(ret), 0644)
|
||||||
check(err)
|
check(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Gen(inFile string, src any) string {
|
func Gen(pkgPath, inFile string, src any) string {
|
||||||
fset := token.NewFileSet()
|
fset := token.NewFileSet()
|
||||||
f, err := parser.ParseFile(fset, inFile, src, parser.ParseComments)
|
f, err := parser.ParseFile(fset, inFile, src, parser.ParseComments)
|
||||||
check(err)
|
check(err)
|
||||||
|
|
||||||
files := []*ast.File{f}
|
files := []*ast.File{f}
|
||||||
name := f.Name.Name
|
name := f.Name.Name
|
||||||
pkg := types.NewPackage(name, name)
|
if pkgPath == "" {
|
||||||
|
pkgPath = name
|
||||||
|
}
|
||||||
|
pkg := types.NewPackage(pkgPath, name)
|
||||||
|
imp := packages.NewImporter(fset)
|
||||||
ssaPkg, _, err := ssautil.BuildPackage(
|
ssaPkg, _, err := ssautil.BuildPackage(
|
||||||
&types.Config{Importer: importer.Default()}, fset, pkg, files, ssa.SanityCheckFunctions)
|
&types.Config{Importer: imp}, fset, pkg, files, ssa.SanityCheckFunctions)
|
||||||
check(err)
|
check(err)
|
||||||
|
|
||||||
ssaPkg.WriteTo(os.Stderr)
|
ssaPkg.WriteTo(os.Stderr)
|
||||||
|
|
||||||
prog := llssa.NewProgram(nil)
|
prog := llssa.NewProgram(nil)
|
||||||
ret, err := cl.NewPackage(prog, ssaPkg, nil)
|
ret, err := cl.NewPackage(prog, ssaPkg, files)
|
||||||
check(err)
|
check(err)
|
||||||
|
|
||||||
return ret.String()
|
return ret.String()
|
||||||
68
internal/llgen/llgenf.go
Normal file
68
internal/llgen/llgenf.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* 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 llgen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/types"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/cl"
|
||||||
|
"golang.org/x/tools/go/packages"
|
||||||
|
"golang.org/x/tools/go/ssa"
|
||||||
|
"golang.org/x/tools/go/ssa/ssautil"
|
||||||
|
|
||||||
|
llssa "github.com/goplus/llgo/ssa"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
loadFiles = packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles
|
||||||
|
loadImports = loadFiles | packages.NeedImports
|
||||||
|
loadTypes = loadImports | packages.NeedTypes | packages.NeedTypesSizes
|
||||||
|
loadSyntax = loadTypes | packages.NeedSyntax | packages.NeedTypesInfo
|
||||||
|
)
|
||||||
|
|
||||||
|
func GenFrom(fileOrPkg string) string {
|
||||||
|
cfg := &packages.Config{
|
||||||
|
Mode: loadSyntax,
|
||||||
|
}
|
||||||
|
initial, err := packages.Load(cfg, fileOrPkg)
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
_, pkgs := ssautil.AllPackages(initial, ssa.SanityCheckFunctions)
|
||||||
|
|
||||||
|
pkg := initial[0]
|
||||||
|
ssaPkg := pkgs[0]
|
||||||
|
ssaPkg.Build()
|
||||||
|
|
||||||
|
prog := llssa.NewProgram(nil)
|
||||||
|
prog.SetRuntime(func() *types.Package {
|
||||||
|
rt, err := packages.Load(cfg, llssa.PkgRuntime)
|
||||||
|
check(err)
|
||||||
|
return rt[0].Types
|
||||||
|
})
|
||||||
|
|
||||||
|
ret, err := cl.NewPackage(prog, ssaPkg, pkg.Syntax)
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
return ret.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func DoFile(fileOrPkg, outFile string) {
|
||||||
|
ret := GenFrom(fileOrPkg)
|
||||||
|
err := os.WriteFile(outFile, []byte(ret), 0644)
|
||||||
|
check(err)
|
||||||
|
}
|
||||||
48
internal/mod/mod.go
Normal file
48
internal/mod/mod.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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 mod
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/goplus/mod"
|
||||||
|
"github.com/goplus/mod/gopmod"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Module represents a Go module.
|
||||||
|
type Module = gopmod.Module
|
||||||
|
|
||||||
|
// Load loads a Go module from a directory.
|
||||||
|
func Load(dir string) (ret *Module, pkgPath string, err error) {
|
||||||
|
if dir, err = filepath.Abs(dir); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, gomod, err := mod.FindGoMod(dir)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ret, err = gopmod.LoadFrom(gomod, ""); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
relPath, err := filepath.Rel(ret.Root(), dir)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pkgPath = path.Join(ret.Path(), filepath.ToSlash(relPath))
|
||||||
|
return
|
||||||
|
}
|
||||||
110
internal/projs/proj.go
Normal file
110
internal/projs/proj.go
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* 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 projs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"path/filepath"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type Proj = interface {
|
||||||
|
projObj()
|
||||||
|
}
|
||||||
|
|
||||||
|
type FilesProj struct {
|
||||||
|
Files []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type PkgPathProj struct {
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
type DirProj struct {
|
||||||
|
Dir string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *FilesProj) projObj() {}
|
||||||
|
func (p *PkgPathProj) projObj() {}
|
||||||
|
func (p *DirProj) projObj() {}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func ParseOne(args ...string) (proj Proj, next []string, err error) {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return nil, nil, syscall.ENOENT
|
||||||
|
}
|
||||||
|
arg := args[0]
|
||||||
|
if isFile(arg) {
|
||||||
|
n := 1
|
||||||
|
for n < len(args) && isFile(args[n]) {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
return &FilesProj{Files: args[:n]}, args[n:], nil
|
||||||
|
}
|
||||||
|
if isLocal(arg) {
|
||||||
|
return &DirProj{Dir: arg}, args[1:], nil
|
||||||
|
}
|
||||||
|
return &PkgPathProj{Path: arg}, args[1:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isFile(fname string) bool {
|
||||||
|
n := len(filepath.Ext(fname))
|
||||||
|
return n > 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func isLocal(ns string) bool {
|
||||||
|
if len(ns) > 0 {
|
||||||
|
switch c := ns[0]; c {
|
||||||
|
case '/', '\\', '.':
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return len(ns) >= 2 && ns[1] == ':' && ('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func ParseAll(args ...string) (projs []Proj, err error) {
|
||||||
|
var hasFiles, hasNotFiles bool
|
||||||
|
for {
|
||||||
|
proj, next, e := ParseOne(args...)
|
||||||
|
if e != nil {
|
||||||
|
if hasFiles && hasNotFiles {
|
||||||
|
return nil, ErrMixedFilesProj
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, ok := proj.(*FilesProj); ok {
|
||||||
|
hasFiles = true
|
||||||
|
} else {
|
||||||
|
hasNotFiles = true
|
||||||
|
}
|
||||||
|
projs = append(projs, proj)
|
||||||
|
args = next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrMixedFilesProj = errors.New("mixed files project")
|
||||||
|
)
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
270
internal/runtime/llgo_autogen.ll
Normal file
270
internal/runtime/llgo_autogen.ll
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
; ModuleID = 'github.com/goplus/llgo/internal/runtime'
|
||||||
|
source_filename = "github.com/goplus/llgo/internal/runtime"
|
||||||
|
|
||||||
|
%"github.com/goplus/llgo/internal/runtime.iface" = type { ptr, ptr }
|
||||||
|
%"github.com/goplus/llgo/internal/runtime.itab" = type { ptr, ptr, i32, [4 x i8], [1 x i64] }
|
||||||
|
%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 }
|
||||||
|
%"github.com/goplus/llgo/internal/runtime.Slice" = type { ptr, i64, i64 }
|
||||||
|
%"github.com/goplus/llgo/internal/abi.Type" = type { i64, i64, i32, i8, i8, i8, i8, ptr, ptr, i32, i32 }
|
||||||
|
|
||||||
|
@"github.com/goplus/llgo/internal/runtime.TyAny" = global ptr null
|
||||||
|
@"github.com/goplus/llgo/internal/runtime.basicTypes" = global ptr null
|
||||||
|
@"github.com/goplus/llgo/internal/runtime.init$guard" = global ptr null
|
||||||
|
@"github.com/goplus/llgo/internal/runtime.sizeBasicTypes" = global ptr null
|
||||||
|
|
||||||
|
define ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = call ptr @malloc(i64 %0)
|
||||||
|
ret ptr %1
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = getelementptr inbounds ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 %0
|
||||||
|
%2 = load ptr, ptr %1, align 8
|
||||||
|
ret ptr %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define { i64, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %1) {
|
||||||
|
_llgo_0:
|
||||||
|
%2 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8
|
||||||
|
store %"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %2, align 8
|
||||||
|
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 0
|
||||||
|
%4 = load ptr, ptr %3, align 8
|
||||||
|
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 1
|
||||||
|
%6 = load ptr, ptr %5, align 8
|
||||||
|
%7 = icmp eq ptr %6, %1
|
||||||
|
br i1 %7, label %_llgo_1, label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
%8 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 1
|
||||||
|
%9 = load ptr, ptr %8, align 8
|
||||||
|
%10 = ptrtoint ptr %9 to i64
|
||||||
|
%mrv = insertvalue { i64, i1 } poison, i64 %10, 0
|
||||||
|
%mrv1 = insertvalue { i64, i1 } %mrv, i1 true, 1
|
||||||
|
ret { i64, i1 } %mrv1
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_0
|
||||||
|
ret { i64, i1 } zeroinitializer
|
||||||
|
}
|
||||||
|
|
||||||
|
define %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.EmptyString"() {
|
||||||
|
_llgo_0:
|
||||||
|
%0 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %0, i32 0, i32 0
|
||||||
|
%2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %0, i32 0, i32 1
|
||||||
|
store ptr null, ptr %1, align 8
|
||||||
|
store i64 0, ptr %2, align 4
|
||||||
|
%3 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %0, align 8
|
||||||
|
ret %"github.com/goplus/llgo/internal/runtime.String" %3
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @"github.com/goplus/llgo/internal/runtime.I2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %1) {
|
||||||
|
_llgo_0:
|
||||||
|
%2 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8
|
||||||
|
store %"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %2, align 8
|
||||||
|
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 0
|
||||||
|
%4 = load ptr, ptr %3, align 8
|
||||||
|
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 1
|
||||||
|
%6 = load ptr, ptr %5, align 8
|
||||||
|
%7 = icmp eq ptr %6, %1
|
||||||
|
br i1 %7, label %_llgo_1, label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
%8 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 1
|
||||||
|
%9 = load ptr, ptr %8, align 8
|
||||||
|
%10 = ptrtoint ptr %9 to i64
|
||||||
|
ret i64 %10
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_0
|
||||||
|
%11 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyString"([21 x i8] c"I2Int: type mismatch\00")
|
||||||
|
unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
define %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAny"(ptr %0, ptr %1) {
|
||||||
|
_llgo_0:
|
||||||
|
%2 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8
|
||||||
|
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 0
|
||||||
|
%4 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16)
|
||||||
|
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 0
|
||||||
|
%6 = load ptr, ptr @"github.com/goplus/llgo/internal/runtime.TyAny", align 8
|
||||||
|
%7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 1
|
||||||
|
%8 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 2
|
||||||
|
%9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 4
|
||||||
|
%10 = getelementptr inbounds i64, ptr %9, i64 0
|
||||||
|
store ptr %6, ptr %5, align 8
|
||||||
|
store ptr %0, ptr %7, align 8
|
||||||
|
store i32 0, ptr %8, align 4
|
||||||
|
store i64 0, ptr %10, align 4
|
||||||
|
%11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 1
|
||||||
|
store ptr %4, ptr %3, align 8
|
||||||
|
store ptr %1, ptr %11, align 8
|
||||||
|
%12 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, align 8
|
||||||
|
ret %"github.com/goplus/llgo/internal/runtime.iface" %12
|
||||||
|
}
|
||||||
|
|
||||||
|
define %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %0, i64 %1) {
|
||||||
|
_llgo_0:
|
||||||
|
%2 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8
|
||||||
|
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 0
|
||||||
|
%4 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16)
|
||||||
|
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 0
|
||||||
|
%6 = load ptr, ptr @"github.com/goplus/llgo/internal/runtime.TyAny", align 8
|
||||||
|
%7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 1
|
||||||
|
%8 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 2
|
||||||
|
%9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 4
|
||||||
|
%10 = getelementptr inbounds i64, ptr %9, i64 0
|
||||||
|
store ptr %6, ptr %5, align 8
|
||||||
|
store ptr %0, ptr %7, align 8
|
||||||
|
store i32 0, ptr %8, align 4
|
||||||
|
store i64 0, ptr %10, align 4
|
||||||
|
%11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 1
|
||||||
|
%12 = inttoptr i64 %1 to ptr
|
||||||
|
store ptr %4, ptr %3, align 8
|
||||||
|
store ptr %12, ptr %11, align 8
|
||||||
|
%13 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, align 8
|
||||||
|
ret %"github.com/goplus/llgo/internal/runtime.iface" %13
|
||||||
|
}
|
||||||
|
|
||||||
|
define %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyString"(%"github.com/goplus/llgo/internal/runtime.String" %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16)
|
||||||
|
store %"github.com/goplus/llgo/internal/runtime.String" %0, ptr %1, align 8
|
||||||
|
%2 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8
|
||||||
|
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 0
|
||||||
|
%4 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16)
|
||||||
|
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 0
|
||||||
|
%6 = load ptr, ptr @"github.com/goplus/llgo/internal/runtime.TyAny", align 8
|
||||||
|
%7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 1
|
||||||
|
%8 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 24)
|
||||||
|
%9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 2
|
||||||
|
%10 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 4
|
||||||
|
%11 = getelementptr inbounds i64, ptr %10, i64 0
|
||||||
|
store ptr %6, ptr %5, align 8
|
||||||
|
store ptr %8, ptr %7, align 8
|
||||||
|
store i32 0, ptr %9, align 4
|
||||||
|
store i64 0, ptr %11, align 4
|
||||||
|
%12 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 1
|
||||||
|
store ptr %4, ptr %3, align 8
|
||||||
|
store ptr %1, ptr %12, align 8
|
||||||
|
%13 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, align 8
|
||||||
|
ret %"github.com/goplus/llgo/internal/runtime.iface" %13
|
||||||
|
}
|
||||||
|
|
||||||
|
define %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeInterface"(ptr %0, ptr %1, ptr %2) {
|
||||||
|
_llgo_0:
|
||||||
|
%3 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8
|
||||||
|
%4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %3, i32 0, i32 0
|
||||||
|
%5 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16)
|
||||||
|
%6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %5, i32 0, i32 0
|
||||||
|
%7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %5, i32 0, i32 1
|
||||||
|
%8 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %5, i32 0, i32 2
|
||||||
|
%9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %5, i32 0, i32 4
|
||||||
|
%10 = getelementptr inbounds i64, ptr %9, i64 0
|
||||||
|
store ptr %0, ptr %6, align 8
|
||||||
|
store ptr %1, ptr %7, align 8
|
||||||
|
store i32 0, ptr %8, align 4
|
||||||
|
store i64 0, ptr %10, align 4
|
||||||
|
%11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %3, i32 0, i32 1
|
||||||
|
store ptr %5, ptr %4, align 8
|
||||||
|
store ptr %2, ptr %11, align 8
|
||||||
|
%12 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %3, align 8
|
||||||
|
ret %"github.com/goplus/llgo/internal/runtime.iface" %12
|
||||||
|
}
|
||||||
|
|
||||||
|
declare ptr @malloc(i64)
|
||||||
|
|
||||||
|
define %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NilSlice"() {
|
||||||
|
_llgo_0:
|
||||||
|
%0 = alloca %"github.com/goplus/llgo/internal/runtime.Slice", align 8
|
||||||
|
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %0, i32 0, i32 0
|
||||||
|
%2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %0, i32 0, i32 1
|
||||||
|
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %0, i32 0, i32 2
|
||||||
|
store ptr null, ptr %1, align 8
|
||||||
|
store i64 0, ptr %2, align 4
|
||||||
|
store i64 0, ptr %3, align 4
|
||||||
|
%4 = load %"github.com/goplus/llgo/internal/runtime.Slice", ptr %0, align 8
|
||||||
|
ret %"github.com/goplus/llgo/internal/runtime.Slice" %4
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16)
|
||||||
|
%2 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.Type", ptr %1, i32 0, i32 0
|
||||||
|
%3 = getelementptr inbounds i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 %0
|
||||||
|
%4 = load i64, ptr %3, align 4
|
||||||
|
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.Type", ptr %1, i32 0, i32 6
|
||||||
|
%6 = trunc i64 %0 to i8
|
||||||
|
store i64 %4, ptr %2, align 4
|
||||||
|
store i8 %6, ptr %5, align 1
|
||||||
|
ret ptr %1
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @"github.com/goplus/llgo/internal/runtime.init"() {
|
||||||
|
_llgo_0:
|
||||||
|
%0 = load i1, ptr @"github.com/goplus/llgo/internal/runtime.init$guard", align 1
|
||||||
|
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
store i1 true, ptr @"github.com/goplus/llgo/internal/runtime.init$guard", align 1
|
||||||
|
call void @"github.com/goplus/llgo/internal/abi.init"()
|
||||||
|
%1 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16)
|
||||||
|
store ptr %1, ptr @"github.com/goplus/llgo/internal/runtime.TyAny", align 8
|
||||||
|
store i64 1, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 1), align 4
|
||||||
|
store i64 8, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 2), align 4
|
||||||
|
store i64 1, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 3), align 4
|
||||||
|
store i64 2, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 4), align 4
|
||||||
|
store i64 4, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 5), align 4
|
||||||
|
store i64 8, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 6), align 4
|
||||||
|
store i64 8, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 7), align 4
|
||||||
|
store i64 1, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 8), align 4
|
||||||
|
store i64 2, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 9), align 4
|
||||||
|
store i64 4, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 10), align 4
|
||||||
|
store i64 8, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 11), align 4
|
||||||
|
store i64 8, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 12), align 4
|
||||||
|
store i64 4, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 13), align 4
|
||||||
|
store i64 8, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 14), align 4
|
||||||
|
store i64 8, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 15), align 4
|
||||||
|
store i64 16, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 16), align 4
|
||||||
|
store i64 16, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 24), align 4
|
||||||
|
%2 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 1)
|
||||||
|
%3 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 2)
|
||||||
|
%4 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 3)
|
||||||
|
%5 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 4)
|
||||||
|
%6 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 5)
|
||||||
|
%7 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 6)
|
||||||
|
%8 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 7)
|
||||||
|
%9 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 8)
|
||||||
|
%10 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 9)
|
||||||
|
%11 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 10)
|
||||||
|
%12 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 11)
|
||||||
|
%13 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 12)
|
||||||
|
%14 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 13)
|
||||||
|
%15 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 14)
|
||||||
|
%16 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 15)
|
||||||
|
%17 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 16)
|
||||||
|
%18 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 24)
|
||||||
|
store ptr %2, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 1), align 8
|
||||||
|
store ptr %3, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 2), align 8
|
||||||
|
store ptr %4, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 3), align 8
|
||||||
|
store ptr %5, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 4), align 8
|
||||||
|
store ptr %6, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 5), align 8
|
||||||
|
store ptr %7, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 6), align 8
|
||||||
|
store ptr %8, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 7), align 8
|
||||||
|
store ptr %9, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 8), align 8
|
||||||
|
store ptr %10, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 9), align 8
|
||||||
|
store ptr %11, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 10), align 8
|
||||||
|
store ptr %12, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 11), align 8
|
||||||
|
store ptr %13, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 12), align 8
|
||||||
|
store ptr %14, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 13), align 8
|
||||||
|
store ptr %15, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 14), align 8
|
||||||
|
store ptr %16, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 15), align 8
|
||||||
|
store ptr %17, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 16), align 8
|
||||||
|
store ptr %18, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 24), align 8
|
||||||
|
br label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/internal/abi.init"()
|
||||||
37
internal/runtime/runtime2.go
Normal file
37
internal/runtime/runtime2.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type iface struct {
|
||||||
|
tab *itab
|
||||||
|
data unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
type eface struct {
|
||||||
|
_type *_type
|
||||||
|
data unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
func efaceOf(ep *any) *eface {
|
||||||
|
return (*eface)(unsafe.Pointer(ep))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// layout of Itab known to compilers
|
||||||
|
// allocated in non-garbage-collected memory
|
||||||
|
// Needs to be in sync with
|
||||||
|
// ../cmd/compile/internal/reflectdata/reflect.go:/^func.WriteTabs.
|
||||||
|
type itab struct {
|
||||||
|
inter *interfacetype
|
||||||
|
_type *_type
|
||||||
|
hash uint32 // copy of _type.hash. Used for type switches.
|
||||||
|
_ [4]byte
|
||||||
|
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
|
||||||
|
}
|
||||||
18
internal/runtime/type.go
Normal file
18
internal/runtime/type.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Runtime type representation.
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/goplus/llgo/internal/abi"
|
||||||
|
)
|
||||||
|
|
||||||
|
// type nameOff = abi.NameOff
|
||||||
|
// type typeOff = abi.TypeOff
|
||||||
|
|
||||||
|
type _type = abi.Type
|
||||||
|
|
||||||
|
type interfacetype = abi.InterfaceType
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2023 The GoPlus Authors (goplus.org). All rights reserved.
|
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -14,11 +14,18 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package llgo
|
package runtime
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
import "unsafe"
|
||||||
|
|
||||||
type Config struct {
|
const (
|
||||||
|
LLGoPackage = true
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:linkname Malloc C.malloc
|
||||||
|
func Malloc(size uintptr) unsafe.Pointer
|
||||||
|
|
||||||
|
// Alloc allocates memory.
|
||||||
|
func Alloc(size uintptr) unsafe.Pointer {
|
||||||
|
return Malloc(size)
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
73
internal/runtime/z_iface.go
Normal file
73
internal/runtime/z_iface.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* 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 runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/internal/abi"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Interface = iface
|
||||||
|
|
||||||
|
type InterfaceType = abi.InterfaceType
|
||||||
|
|
||||||
|
var (
|
||||||
|
TyAny = &InterfaceType{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func MakeAnyInt(typ *Type, data uintptr) Interface {
|
||||||
|
return Interface{
|
||||||
|
tab: &itab{inter: TyAny, _type: typ, hash: 0, fun: [1]uintptr{0}},
|
||||||
|
data: unsafe.Pointer(data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeAnyString(data string) Interface {
|
||||||
|
return Interface{
|
||||||
|
tab: &itab{inter: TyAny, _type: Basic(abi.String), hash: 0, fun: [1]uintptr{0}},
|
||||||
|
data: unsafe.Pointer(&data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeAny(typ *Type, data unsafe.Pointer) Interface {
|
||||||
|
return Interface{
|
||||||
|
tab: &itab{inter: TyAny, _type: typ, hash: 0, fun: [1]uintptr{0}},
|
||||||
|
data: data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeInterface(inter *InterfaceType, typ *Type, data unsafe.Pointer) Interface {
|
||||||
|
return Interface{
|
||||||
|
tab: &itab{inter: inter, _type: typ, hash: 0, fun: [1]uintptr{0}},
|
||||||
|
data: data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func I2Int(v Interface, t *Type) uintptr {
|
||||||
|
if v.tab._type == t {
|
||||||
|
return uintptr(v.data)
|
||||||
|
}
|
||||||
|
panic("I2Int: type mismatch")
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckI2Int(v Interface, t *Type) (uintptr, bool) {
|
||||||
|
if v.tab._type == t {
|
||||||
|
return uintptr(v.data), true
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
33
internal/runtime/z_slice.go
Normal file
33
internal/runtime/z_slice.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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 runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Slice is the runtime representation of a slice.
|
||||||
|
type Slice struct {
|
||||||
|
array unsafe.Pointer
|
||||||
|
len int
|
||||||
|
cap int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NilSlice returns a nil slice.
|
||||||
|
func NilSlice() Slice {
|
||||||
|
return Slice{nil, 0, 0}
|
||||||
|
}
|
||||||
37
internal/runtime/z_string.go
Normal file
37
internal/runtime/z_string.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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 runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// String is the runtime representation of a string.
|
||||||
|
// It cannot be used safely or portably and its representation may
|
||||||
|
// change in a later release.
|
||||||
|
//
|
||||||
|
// Unlike reflect.StringHeader, its Data field is sufficient to guarantee the
|
||||||
|
// data it references will not be garbage collected.
|
||||||
|
type String struct {
|
||||||
|
data unsafe.Pointer
|
||||||
|
len int
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmptyString returns an empty string.
|
||||||
|
func EmptyString() String {
|
||||||
|
return String{nil, 0}
|
||||||
|
}
|
||||||
81
internal/runtime/z_type.go
Normal file
81
internal/runtime/z_type.go
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* 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 runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/internal/abi"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Kind = abi.Kind
|
||||||
|
type Type = abi.Type
|
||||||
|
|
||||||
|
func Basic(kind Kind) *Type {
|
||||||
|
return basicTypes[kind]
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
basicTypes = [...]*Type{
|
||||||
|
abi.Bool: basicType(abi.Bool),
|
||||||
|
abi.Int: basicType(abi.Int),
|
||||||
|
abi.Int8: basicType(abi.Int8),
|
||||||
|
abi.Int16: basicType(abi.Int16),
|
||||||
|
abi.Int32: basicType(abi.Int32),
|
||||||
|
abi.Int64: basicType(abi.Int64),
|
||||||
|
abi.Uint: basicType(abi.Uint),
|
||||||
|
abi.Uint8: basicType(abi.Uint8),
|
||||||
|
abi.Uint16: basicType(abi.Uint16),
|
||||||
|
abi.Uint32: basicType(abi.Uint32),
|
||||||
|
abi.Uint64: basicType(abi.Uint64),
|
||||||
|
abi.Uintptr: basicType(abi.Uintptr),
|
||||||
|
abi.Float32: basicType(abi.Float32),
|
||||||
|
abi.Float64: basicType(abi.Float64),
|
||||||
|
abi.Complex64: basicType(abi.Complex64),
|
||||||
|
abi.Complex128: basicType(abi.Complex128),
|
||||||
|
abi.String: basicType(abi.String),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
sizeBasicTypes = [...]uintptr{
|
||||||
|
abi.Bool: unsafe.Sizeof(false),
|
||||||
|
abi.Int: unsafe.Sizeof(0),
|
||||||
|
abi.Int8: 1,
|
||||||
|
abi.Int16: 2,
|
||||||
|
abi.Int32: 4,
|
||||||
|
abi.Int64: 8,
|
||||||
|
abi.Uint: unsafe.Sizeof(uint(0)),
|
||||||
|
abi.Uint8: 1,
|
||||||
|
abi.Uint16: 2,
|
||||||
|
abi.Uint32: 4,
|
||||||
|
abi.Uint64: 8,
|
||||||
|
abi.Uintptr: unsafe.Sizeof(uintptr(0)),
|
||||||
|
abi.Float32: 4,
|
||||||
|
abi.Float64: 8,
|
||||||
|
abi.Complex64: 8,
|
||||||
|
abi.Complex128: 16,
|
||||||
|
abi.String: unsafe.Sizeof(String{}),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func basicType(kind abi.Kind) *Type {
|
||||||
|
return &abi.Type{
|
||||||
|
Size_: sizeBasicTypes[kind],
|
||||||
|
Kind_: uint8(kind),
|
||||||
|
}
|
||||||
|
}
|
||||||
36
ssa/cl_test.go
Normal file
36
ssa/cl_test.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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 ssa_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/cl/cltest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFromTestcgo(t *testing.T) {
|
||||||
|
cltest.FromDir(t, "", "../cl/_testcgo", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFromTestdata(t *testing.T) {
|
||||||
|
cltest.FromDir(t, "", "../cl/_testdata", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRuntime(t *testing.T) {
|
||||||
|
cltest.Pkg(t, "github.com/goplus/llgo/internal/runtime", "../internal/runtime/llgo_autogen.ll")
|
||||||
|
cltest.Pkg(t, "github.com/goplus/llgo/internal/abi", "../internal/abi/llgo_autogen.ll")
|
||||||
|
}
|
||||||
@@ -106,6 +106,7 @@ func (g Global) Init(v Expr) {
|
|||||||
// respectively, and is nil in the generic method.
|
// respectively, and is nil in the generic method.
|
||||||
type aFunction struct {
|
type aFunction struct {
|
||||||
Expr
|
Expr
|
||||||
|
pkg Package
|
||||||
prog Program
|
prog Program
|
||||||
blks []BasicBlock
|
blks []BasicBlock
|
||||||
|
|
||||||
@@ -116,9 +117,9 @@ type aFunction struct {
|
|||||||
// Function represents a function or method.
|
// Function represents a function or method.
|
||||||
type Function = *aFunction
|
type Function = *aFunction
|
||||||
|
|
||||||
func newFunction(fn llvm.Value, t Type, prog Program) Function {
|
func newFunction(fn llvm.Value, t Type, pkg Package, prog Program) Function {
|
||||||
params, hasVArg := newParams(t, prog)
|
params, hasVArg := newParams(t, prog)
|
||||||
return &aFunction{Expr{fn, t}, prog, nil, params, hasVArg}
|
return &aFunction{Expr{fn, t}, pkg, prog, nil, params, hasVArg}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newParams(fn Type, prog Program) (params []Type, hasVArg bool) {
|
func newParams(fn Type, prog Program) (params []Type, hasVArg bool) {
|
||||||
@@ -145,7 +146,8 @@ func (p Function) Param(i int) Expr {
|
|||||||
func (p Function) NewBuilder() Builder {
|
func (p Function) NewBuilder() Builder {
|
||||||
prog := p.prog
|
prog := p.prog
|
||||||
b := prog.ctx.NewBuilder()
|
b := prog.ctx.NewBuilder()
|
||||||
b.Finalize()
|
// TODO(xsw): Finalize may cause panic, so comment it.
|
||||||
|
// b.Finalize()
|
||||||
return &aBuilder{b, p, prog}
|
return &aBuilder{b, p, prog}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
343
ssa/expr.go
343
ssa/expr.go
@@ -23,6 +23,7 @@ import (
|
|||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
"log"
|
"log"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/llvm"
|
"github.com/goplus/llvm"
|
||||||
)
|
)
|
||||||
@@ -34,6 +35,36 @@ type Expr struct {
|
|||||||
Type
|
Type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// TypeOf returns the type of the expression.
|
||||||
|
func (v Expr) TypeOf() types.Type {
|
||||||
|
return v.t
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Do evaluates the delay expression and returns the result.
|
||||||
|
func (v Expr) Do() Expr {
|
||||||
|
if vt := v.Type; vt.kind == vkDelayExpr {
|
||||||
|
return vt.t.(delayExprTy)()
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelayExpr returns a delay expression.
|
||||||
|
func DelayExpr(f func() Expr) Expr {
|
||||||
|
return Expr{Type: &aType{t: delayExprTy(f), kind: vkDelayExpr}}
|
||||||
|
}
|
||||||
|
|
||||||
|
type delayExprTy func() Expr
|
||||||
|
|
||||||
|
func (p delayExprTy) Underlying() types.Type {
|
||||||
|
panic("don't call")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p delayExprTy) String() string {
|
||||||
|
return "delayExpr"
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
func llvmValues(vals []Expr) []llvm.Value {
|
func llvmValues(vals []Expr) []llvm.Value {
|
||||||
@@ -46,10 +77,26 @@ func llvmValues(vals []Expr) []llvm.Value {
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Null returns a null constant expression.
|
||||||
func (p Program) Null(t Type) Expr {
|
func (p Program) Null(t Type) Expr {
|
||||||
return Expr{llvm.ConstNull(t.ll), t}
|
return Expr{llvm.ConstNull(t.ll), t}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CStringVal returns a c-style string constant expression.
|
||||||
|
func (p Program) CStringVal(v string) Expr {
|
||||||
|
t := p.CString()
|
||||||
|
return Expr{llvm.ConstString(v, true), t}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringVal returns string constant expression.
|
||||||
|
func (p Program) StringVal(v string) Expr {
|
||||||
|
t := p.String()
|
||||||
|
cstr := llvm.ConstString(v, true)
|
||||||
|
// TODO(xsw): cstr => gostring
|
||||||
|
return Expr{cstr, t}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolVal returns a boolean constant expression.
|
||||||
func (p Program) BoolVal(v bool) Expr {
|
func (p Program) BoolVal(v bool) Expr {
|
||||||
t := p.Bool()
|
t := p.Bool()
|
||||||
var bv uint64
|
var bv uint64
|
||||||
@@ -60,15 +107,19 @@ func (p Program) BoolVal(v bool) Expr {
|
|||||||
return Expr{ret, t}
|
return Expr{ret, t}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IntVal returns an integer constant expression.
|
||||||
func (p Program) IntVal(v uint64, t Type) Expr {
|
func (p Program) IntVal(v uint64, t Type) Expr {
|
||||||
ret := llvm.ConstInt(t.ll, v, false)
|
ret := llvm.ConstInt(t.ll, v, false)
|
||||||
return Expr{ret, t}
|
return Expr{ret, t}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
case int:
|
case int:
|
||||||
return p.IntVal(uint64(v), p.Int())
|
return p.IntVal(uint64(v), p.Int())
|
||||||
|
case uintptr:
|
||||||
|
return p.IntVal(uint64(v), p.Uintptr())
|
||||||
case bool:
|
case bool:
|
||||||
return p.BoolVal(v)
|
return p.BoolVal(v)
|
||||||
case float64:
|
case float64:
|
||||||
@@ -79,17 +130,24 @@ func (p Program) Val(v interface{}) Expr {
|
|||||||
panic("todo")
|
panic("todo")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Const returns a constant expression.
|
||||||
func (b Builder) Const(v constant.Value, typ Type) Expr {
|
func (b Builder) Const(v constant.Value, typ Type) Expr {
|
||||||
|
prog := b.prog
|
||||||
|
if v == nil {
|
||||||
|
return prog.Null(typ)
|
||||||
|
}
|
||||||
switch t := typ.t.(type) {
|
switch t := typ.t.(type) {
|
||||||
case *types.Basic:
|
case *types.Basic:
|
||||||
kind := t.Kind()
|
kind := t.Kind()
|
||||||
switch {
|
switch {
|
||||||
case kind == types.Bool:
|
case kind == types.Bool:
|
||||||
return b.prog.BoolVal(constant.BoolVal(v))
|
return prog.BoolVal(constant.BoolVal(v))
|
||||||
case kind >= types.Int && kind <= types.Uintptr:
|
case kind >= types.Int && kind <= types.Uintptr:
|
||||||
if v, exact := constant.Uint64Val(v); exact {
|
if v, exact := constant.Uint64Val(v); exact {
|
||||||
return b.prog.IntVal(v, typ)
|
return prog.IntVal(v, typ)
|
||||||
}
|
}
|
||||||
|
case kind == types.String:
|
||||||
|
return prog.StringVal(constant.StringVal(v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic("todo")
|
panic("todo")
|
||||||
@@ -225,12 +283,12 @@ func (b Builder) BinOp(op token.Token, x, y Expr) Expr {
|
|||||||
case vkSigned:
|
case vkSigned:
|
||||||
pred := intPredOpToLLVM[op-predOpBase]
|
pred := intPredOpToLLVM[op-predOpBase]
|
||||||
return Expr{llvm.CreateICmp(b.impl, pred, x.impl, y.impl), tret}
|
return Expr{llvm.CreateICmp(b.impl, pred, x.impl, y.impl), tret}
|
||||||
case vkUnsigned:
|
case vkUnsigned, vkPtr:
|
||||||
pred := uintPredOpToLLVM[op-predOpBase]
|
pred := uintPredOpToLLVM[op-predOpBase]
|
||||||
return Expr{llvm.CreateICmp(b.impl, pred, x.impl, y.impl), tret}
|
return Expr{llvm.CreateICmp(b.impl, pred, x.impl, y.impl), tret}
|
||||||
case vkFloat:
|
case vkFloat:
|
||||||
pred := floatPredOpToLLVM[op-predOpBase]
|
pred := floatPredOpToLLVM[op-predOpBase]
|
||||||
return Expr{llvm.ConstFCmp(pred, x.impl, y.impl), tret}
|
return Expr{llvm.CreateFCmp(b.impl, pred, x.impl, y.impl), tret}
|
||||||
case vkString, vkComplex, vkBool:
|
case vkString, vkComplex, vkBool:
|
||||||
panic("todo")
|
panic("todo")
|
||||||
}
|
}
|
||||||
@@ -258,7 +316,7 @@ func (b Builder) UnOp(op token.Token, x Expr) Expr {
|
|||||||
// Load returns the value at the pointer ptr.
|
// Load returns the value at the pointer ptr.
|
||||||
func (b Builder) Load(ptr Expr) Expr {
|
func (b Builder) Load(ptr Expr) Expr {
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
log.Printf("Load %v\n", ptr.impl.Name())
|
log.Printf("Load %v\n", ptr.impl)
|
||||||
}
|
}
|
||||||
telem := b.prog.Elem(ptr.Type)
|
telem := b.prog.Elem(ptr.Type)
|
||||||
return Expr{llvm.CreateLoad(b.impl, telem.ll, ptr.impl), telem}
|
return Expr{llvm.CreateLoad(b.impl, telem.ll, ptr.impl), telem}
|
||||||
@@ -267,12 +325,42 @@ func (b Builder) Load(ptr Expr) Expr {
|
|||||||
// Store stores val at the pointer ptr.
|
// Store stores val at the pointer ptr.
|
||||||
func (b Builder) Store(ptr, val Expr) Builder {
|
func (b Builder) Store(ptr, val Expr) Builder {
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
log.Printf("Store %v, %v\n", ptr.impl.Name(), val.impl)
|
log.Printf("Store %v, %v\n", ptr.impl, val.impl)
|
||||||
}
|
}
|
||||||
b.impl.CreateStore(val.impl, ptr.impl)
|
b.impl.CreateStore(val.impl, ptr.impl)
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The FieldAddr instruction yields the address of Field of *struct X.
|
||||||
|
//
|
||||||
|
// The field is identified by its index within the field list of the
|
||||||
|
// struct type of X.
|
||||||
|
//
|
||||||
|
// Dynamically, this instruction panics if X evaluates to a nil
|
||||||
|
// pointer.
|
||||||
|
//
|
||||||
|
// Type() returns a (possibly named) *types.Pointer.
|
||||||
|
//
|
||||||
|
// Pos() returns the position of the ast.SelectorExpr.Sel for the
|
||||||
|
// field, if explicit in the source. For implicit selections, returns
|
||||||
|
// the position of the inducing explicit selection. If produced for a
|
||||||
|
// struct literal S{f: e}, it returns the position of the colon; for
|
||||||
|
// S{e} it returns the start of expression e.
|
||||||
|
//
|
||||||
|
// Example printed form:
|
||||||
|
//
|
||||||
|
// t1 = &t0.name [#1]
|
||||||
|
func (b Builder) FieldAddr(x Expr, idx int) Expr {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("FieldAddr %v, %d\n", x.impl, idx)
|
||||||
|
}
|
||||||
|
prog := b.prog
|
||||||
|
tstruc := prog.Elem(x.Type)
|
||||||
|
telem := prog.Field(tstruc, idx)
|
||||||
|
pt := prog.Pointer(telem)
|
||||||
|
return Expr{llvm.CreateStructGEP(b.impl, tstruc.ll, x.impl, idx), pt}
|
||||||
|
}
|
||||||
|
|
||||||
// The IndexAddr instruction yields the address of the element at
|
// The IndexAddr instruction yields the address of the element at
|
||||||
// index `idx` of collection `x`. `idx` is an integer expression.
|
// index `idx` of collection `x`. `idx` is an integer expression.
|
||||||
//
|
//
|
||||||
@@ -315,23 +403,240 @@ func (b Builder) IndexAddr(x, idx Expr) Expr {
|
|||||||
//
|
//
|
||||||
// t0 = local int
|
// t0 = local int
|
||||||
// t1 = new int
|
// t1 = new int
|
||||||
func (b Builder) Alloc(t Type, heap bool) (ret Expr) {
|
func (b Builder) Alloc(t *types.Pointer, heap bool) (ret Expr) {
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
log.Printf("Alloc %v, %v\n", t.ll, heap)
|
log.Printf("Alloc %v, %v\n", t, heap)
|
||||||
}
|
}
|
||||||
telem := b.prog.Elem(t)
|
prog := b.prog
|
||||||
|
telem := t.Elem()
|
||||||
if heap {
|
if heap {
|
||||||
ret.impl = llvm.CreateAlloca(b.impl, telem.ll)
|
pkg := b.fn.pkg
|
||||||
|
size := unsafe.Sizeof(telem)
|
||||||
|
ret = b.Call(pkg.rtFunc("Alloc"), prog.Val(size))
|
||||||
} else {
|
} else {
|
||||||
panic("todo")
|
ret.impl = llvm.CreateAlloca(b.impl, prog.Type(telem).ll)
|
||||||
}
|
}
|
||||||
// TODO: zero-initialize
|
// TODO(xsw): zero-initialize
|
||||||
ret.Type = t
|
ret.Type = prog.Type(t)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The ChangeType instruction applies to X a value-preserving type
|
||||||
|
// change to Type().
|
||||||
|
//
|
||||||
|
// Type changes are permitted:
|
||||||
|
// - between a named type and its underlying type.
|
||||||
|
// - between two named types of the same underlying type.
|
||||||
|
// - between (possibly named) pointers to identical base types.
|
||||||
|
// - from a bidirectional channel to a read- or write-channel,
|
||||||
|
// optionally adding/removing a name.
|
||||||
|
// - between a type (t) and an instance of the type (tσ), i.e.
|
||||||
|
// Type() == σ(X.Type()) (or X.Type()== σ(Type())) where
|
||||||
|
// σ is the type substitution of Parent().TypeParams by
|
||||||
|
// Parent().TypeArgs.
|
||||||
|
//
|
||||||
|
// This operation cannot fail dynamically.
|
||||||
|
//
|
||||||
|
// Type changes may to be to or from a type parameter (or both). All
|
||||||
|
// types in the type set of X.Type() have a value-preserving type
|
||||||
|
// change to all types in the type set of Type().
|
||||||
|
//
|
||||||
|
// Example printed form:
|
||||||
|
//
|
||||||
|
// t1 = changetype *int <- IntPtr (t0)
|
||||||
|
func (b Builder) ChangeType(t Type, x Expr) (ret Expr) {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("ChangeType %v, %v\n", t.t, x.impl)
|
||||||
|
}
|
||||||
|
typ := t.t
|
||||||
|
switch typ.(type) {
|
||||||
|
default:
|
||||||
|
ret.impl = b.impl.CreateBitCast(x.impl, t.ll, "bitCast")
|
||||||
|
ret.Type = b.prog.Type(typ)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Convert instruction yields the conversion of value X to type
|
||||||
|
// Type(). One or both of those types is basic (but possibly named).
|
||||||
|
//
|
||||||
|
// A conversion may change the value and representation of its operand.
|
||||||
|
// Conversions are permitted:
|
||||||
|
// - between real numeric types.
|
||||||
|
// - between complex numeric types.
|
||||||
|
// - between string and []byte or []rune.
|
||||||
|
// - between pointers and unsafe.Pointer.
|
||||||
|
// - between unsafe.Pointer and uintptr.
|
||||||
|
// - from (Unicode) integer to (UTF-8) string.
|
||||||
|
//
|
||||||
|
// A conversion may imply a type name change also.
|
||||||
|
//
|
||||||
|
// Conversions may to be to or from a type parameter. All types in
|
||||||
|
// the type set of X.Type() can be converted to all types in the type
|
||||||
|
// set of Type().
|
||||||
|
//
|
||||||
|
// This operation cannot fail dynamically.
|
||||||
|
//
|
||||||
|
// Conversions of untyped string/number/bool constants to a specific
|
||||||
|
// representation are eliminated during SSA construction.
|
||||||
|
//
|
||||||
|
// Pos() returns the ast.CallExpr.Lparen, if the instruction arose
|
||||||
|
// from an explicit conversion in the source.
|
||||||
|
//
|
||||||
|
// Example printed form:
|
||||||
|
//
|
||||||
|
// t1 = convert []byte <- string (t0)
|
||||||
|
func (b Builder) Convert(t Type, x Expr) (ret Expr) {
|
||||||
|
typ := t.t
|
||||||
|
ret.Type = b.prog.Type(typ)
|
||||||
|
switch und := typ.Underlying().(type) {
|
||||||
|
case *types.Basic:
|
||||||
|
kind := und.Kind()
|
||||||
|
switch {
|
||||||
|
case kind >= types.Int && kind <= types.Uintptr:
|
||||||
|
ret.impl = castInt(b.impl, x.impl, t.ll)
|
||||||
|
return
|
||||||
|
case kind == types.UnsafePointer:
|
||||||
|
ret.impl = castPtr(b.impl, x.impl, t.ll)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case *types.Pointer:
|
||||||
|
ret.impl = castPtr(b.impl, x.impl, t.ll)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
|
func castInt(b llvm.Builder, x llvm.Value, t llvm.Type) llvm.Value {
|
||||||
|
xt := x.Type()
|
||||||
|
if xt.TypeKind() == llvm.PointerTypeKind {
|
||||||
|
return llvm.CreatePtrToInt(b, x, t)
|
||||||
|
}
|
||||||
|
if xt.IntTypeWidth() <= t.IntTypeWidth() {
|
||||||
|
return llvm.CreateIntCast(b, x, t)
|
||||||
|
}
|
||||||
|
return llvm.CreateTrunc(b, x, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func castPtr(b llvm.Builder, x llvm.Value, t llvm.Type) llvm.Value {
|
||||||
|
if x.Type().TypeKind() == llvm.PointerTypeKind {
|
||||||
|
return llvm.CreatePointerCast(b, x, t)
|
||||||
|
}
|
||||||
|
return llvm.CreateIntToPtr(b, x, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeInterface constructs an instance of an interface type from a
|
||||||
|
// value of a concrete type.
|
||||||
|
//
|
||||||
|
// Use Program.MethodSets.MethodSet(X.Type()) to find the method-set
|
||||||
|
// of X, and Program.MethodValue(m) to find the implementation of a method.
|
||||||
|
//
|
||||||
|
// To construct the zero value of an interface type T, use:
|
||||||
|
//
|
||||||
|
// NewConst(constant.MakeNil(), T, pos)
|
||||||
|
//
|
||||||
|
// Pos() returns the ast.CallExpr.Lparen, if the instruction arose
|
||||||
|
// from an explicit conversion in the source.
|
||||||
|
//
|
||||||
|
// Example printed form:
|
||||||
|
//
|
||||||
|
// t1 = make interface{} <- int (42:int)
|
||||||
|
// t2 = make Stringer <- t0
|
||||||
|
func (b Builder) MakeInterface(inter types.Type, x Expr, mayDelay bool) (ret Expr) {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("MakeInterface %v, %v\n", inter, x.impl)
|
||||||
|
}
|
||||||
|
t := inter.Underlying().(*types.Interface)
|
||||||
|
isAny := t.Empty()
|
||||||
|
fnDo := func() Expr {
|
||||||
|
pkg := b.fn.pkg
|
||||||
|
switch x.kind {
|
||||||
|
case vkSigned, vkUnsigned, vkFloat:
|
||||||
|
fn := pkg.rtFunc("MakeAnyInt")
|
||||||
|
return b.InlineCall(fn, x)
|
||||||
|
case vkString:
|
||||||
|
fn := pkg.rtFunc("MakeAnyString")
|
||||||
|
return b.InlineCall(fn, x)
|
||||||
|
}
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
if mayDelay && isAny {
|
||||||
|
return DelayExpr(fnDo)
|
||||||
|
}
|
||||||
|
return fnDo()
|
||||||
|
}
|
||||||
|
|
||||||
|
// The TypeAssert instruction tests whether interface value X has type
|
||||||
|
// AssertedType.
|
||||||
|
//
|
||||||
|
// If !CommaOk, on success it returns v, the result of the conversion
|
||||||
|
// (defined below); on failure it panics.
|
||||||
|
//
|
||||||
|
// If CommaOk: on success it returns a pair (v, true) where v is the
|
||||||
|
// result of the conversion; on failure it returns (z, false) where z
|
||||||
|
// is AssertedType's zero value. The components of the pair must be
|
||||||
|
// accessed using the Extract instruction.
|
||||||
|
//
|
||||||
|
// If Underlying: tests whether interface value X has the underlying
|
||||||
|
// type AssertedType.
|
||||||
|
//
|
||||||
|
// If AssertedType is a concrete type, TypeAssert checks whether the
|
||||||
|
// dynamic type in interface X is equal to it, and if so, the result
|
||||||
|
// of the conversion is a copy of the value in the interface.
|
||||||
|
//
|
||||||
|
// If AssertedType is an interface, TypeAssert checks whether the
|
||||||
|
// dynamic type of the interface is assignable to it, and if so, the
|
||||||
|
// result of the conversion is a copy of the interface value X.
|
||||||
|
// If AssertedType is a superinterface of X.Type(), the operation will
|
||||||
|
// fail iff the operand is nil. (Contrast with ChangeInterface, which
|
||||||
|
// performs no nil-check.)
|
||||||
|
//
|
||||||
|
// Type() reflects the actual type of the result, possibly a
|
||||||
|
// 2-types.Tuple; AssertedType is the asserted type.
|
||||||
|
//
|
||||||
|
// Depending on the TypeAssert's purpose, Pos may return:
|
||||||
|
// - the ast.CallExpr.Lparen of an explicit T(e) conversion;
|
||||||
|
// - the ast.TypeAssertExpr.Lparen of an explicit e.(T) operation;
|
||||||
|
// - the ast.CaseClause.Case of a case of a type-switch statement;
|
||||||
|
// - the Ident(m).NamePos of an interface method value i.m
|
||||||
|
// (for which TypeAssert may be used to effect the nil check).
|
||||||
|
//
|
||||||
|
// Example printed form:
|
||||||
|
//
|
||||||
|
// t1 = typeassert t0.(int)
|
||||||
|
// t3 = typeassert,ok t2.(T)
|
||||||
|
func (b Builder) TypeAssert(x Expr, assertedTyp Type, commaOk bool) (ret Expr) {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("TypeAssert %v, %v, %v\n", x.impl, assertedTyp.t, commaOk)
|
||||||
|
}
|
||||||
|
switch assertedTyp.kind {
|
||||||
|
case vkSigned, vkUnsigned, vkFloat:
|
||||||
|
pkg := b.fn.pkg
|
||||||
|
fnName := "I2Int"
|
||||||
|
if commaOk {
|
||||||
|
fnName = "CheckI2Int"
|
||||||
|
}
|
||||||
|
fn := pkg.rtFunc(fnName)
|
||||||
|
var kind types.BasicKind
|
||||||
|
switch t := assertedTyp.t.(type) {
|
||||||
|
case *types.Basic:
|
||||||
|
kind = t.Kind()
|
||||||
|
default:
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
typ := b.InlineCall(pkg.rtFunc("Basic"), b.prog.Val(int(kind)))
|
||||||
|
return b.InlineCall(fn, x, typ)
|
||||||
|
}
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// TODO(xsw): make inline call
|
||||||
|
func (b Builder) InlineCall(fn Expr, args ...Expr) (ret Expr) {
|
||||||
|
return b.Call(fn, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// The Call instruction represents a function or method call.
|
// The Call instruction represents a function or method call.
|
||||||
//
|
//
|
||||||
// The Call instruction yields the function result if there is exactly
|
// The Call instruction yields the function result if there is exactly
|
||||||
@@ -346,7 +651,7 @@ func (b Builder) Alloc(t Type, heap bool) (ret Expr) {
|
|||||||
func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
|
func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
fmt.Fprint(&b, "Call @", fn.impl.Name())
|
fmt.Fprint(&b, "Call ", fn.impl.Name())
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
fmt.Fprint(&b, ", ", arg.impl)
|
fmt.Fprint(&b, ", ", arg.impl)
|
||||||
}
|
}
|
||||||
@@ -362,4 +667,14 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A Builtin represents a specific use of a built-in function, e.g. len.
|
||||||
|
//
|
||||||
|
// Builtins are immutable values. Builtins do not have addresses.
|
||||||
|
//
|
||||||
|
// `fn` indicates the function: one of the built-in functions from the
|
||||||
|
// Go spec (excluding "make" and "new").
|
||||||
|
func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
127
ssa/package.go
127
ssa/package.go
@@ -24,6 +24,10 @@ import (
|
|||||||
"golang.org/x/tools/go/types/typeutil"
|
"golang.org/x/tools/go/types/typeutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PkgRuntime = "github.com/goplus/llgo/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
type dbgFlags = int
|
type dbgFlags = int
|
||||||
@@ -94,6 +98,9 @@ type aProgram struct {
|
|||||||
ctx llvm.Context
|
ctx llvm.Context
|
||||||
typs typeutil.Map
|
typs typeutil.Map
|
||||||
|
|
||||||
|
rt *types.Package
|
||||||
|
rtget func() *types.Package
|
||||||
|
|
||||||
target *Target
|
target *Target
|
||||||
td llvm.TargetData
|
td llvm.TargetData
|
||||||
// tm llvm.TargetMachine
|
// tm llvm.TargetMachine
|
||||||
@@ -107,10 +114,20 @@ type aProgram struct {
|
|||||||
voidType llvm.Type
|
voidType llvm.Type
|
||||||
voidPtrTy llvm.Type
|
voidPtrTy llvm.Type
|
||||||
|
|
||||||
|
rtStringTy llvm.Type
|
||||||
|
rtIfaceTy llvm.Type
|
||||||
|
rtSliceTy llvm.Type
|
||||||
|
|
||||||
|
anyTy Type
|
||||||
voidTy Type
|
voidTy Type
|
||||||
boolTy Type
|
boolTy Type
|
||||||
|
cstrTy Type
|
||||||
|
stringTy Type
|
||||||
|
uintptrTy Type
|
||||||
intTy Type
|
intTy Type
|
||||||
f64Ty Type
|
f64Ty Type
|
||||||
|
|
||||||
|
needRuntime bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Program presents a program.
|
// A Program presents a program.
|
||||||
@@ -122,17 +139,73 @@ func NewProgram(target *Target) Program {
|
|||||||
target = &Target{}
|
target = &Target{}
|
||||||
}
|
}
|
||||||
ctx := llvm.NewContext()
|
ctx := llvm.NewContext()
|
||||||
ctx.Finalize()
|
// TODO(xsw): Finalize may cause panic, so comment it.
|
||||||
|
// ctx.Finalize()
|
||||||
td := llvm.NewTargetData("") // TODO(xsw): target config
|
td := llvm.NewTargetData("") // TODO(xsw): target config
|
||||||
return &aProgram{ctx: ctx, target: target, td: td}
|
return &aProgram{ctx: ctx, target: target, td: td}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetRuntime sets the runtime.
|
||||||
|
// Its type can be *types.Package or func() *types.Package.
|
||||||
|
func (p Program) SetRuntime(runtime any) {
|
||||||
|
switch v := runtime.(type) {
|
||||||
|
case *types.Package:
|
||||||
|
p.rt = v
|
||||||
|
case func() *types.Package:
|
||||||
|
p.rtget = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NeedRuntime returns if the current package needs runtime.
|
||||||
|
func (p Program) NeedRuntime() bool {
|
||||||
|
return p.needRuntime
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Program) runtime() *types.Package {
|
||||||
|
if p.rt == nil {
|
||||||
|
p.rt = p.rtget()
|
||||||
|
}
|
||||||
|
p.needRuntime = true
|
||||||
|
return p.rt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Program) rtNamed(name string) *types.Named {
|
||||||
|
return p.runtime().Scope().Lookup(name).Type().(*types.Named)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Program) rtType(name string) Type {
|
||||||
|
return p.Type(p.rtNamed(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Program) rtIface() llvm.Type {
|
||||||
|
if p.rtIfaceTy.IsNil() {
|
||||||
|
p.rtIfaceTy = p.rtType("Interface").ll
|
||||||
|
}
|
||||||
|
return p.rtIfaceTy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Program) rtSlice() llvm.Type {
|
||||||
|
if p.rtSliceTy.IsNil() {
|
||||||
|
p.rtSliceTy = p.rtType("Slice").ll
|
||||||
|
}
|
||||||
|
return p.rtSliceTy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Program) rtString() llvm.Type {
|
||||||
|
if p.rtStringTy.IsNil() {
|
||||||
|
p.rtStringTy = p.rtType("String").ll
|
||||||
|
}
|
||||||
|
return p.rtStringTy
|
||||||
|
}
|
||||||
|
|
||||||
// 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)
|
||||||
mod.Finalize()
|
// TODO(xsw): Finalize may cause panic, so comment it.
|
||||||
|
// mod.Finalize()
|
||||||
fns := make(map[string]Function)
|
fns := make(map[string]Function)
|
||||||
gbls := make(map[string]Global)
|
gbls := make(map[string]Global)
|
||||||
|
p.needRuntime = false
|
||||||
return &aPackage{mod, fns, gbls, p}
|
return &aPackage{mod, fns, gbls, p}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,6 +225,28 @@ func (p Program) Bool() Type {
|
|||||||
return p.boolTy
|
return p.boolTy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p Program) CString() Type {
|
||||||
|
if p.cstrTy == nil { // *int8
|
||||||
|
p.cstrTy = p.Type(types.NewPointer(types.Typ[types.Int8]))
|
||||||
|
}
|
||||||
|
return p.cstrTy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Program) String() Type {
|
||||||
|
if p.stringTy == nil {
|
||||||
|
p.stringTy = p.Type(types.Typ[types.String])
|
||||||
|
}
|
||||||
|
return p.stringTy
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any returns any type.
|
||||||
|
func (p Program) Any() Type {
|
||||||
|
if p.anyTy == nil {
|
||||||
|
p.anyTy = p.Type(tyAny)
|
||||||
|
}
|
||||||
|
return p.anyTy
|
||||||
|
}
|
||||||
|
|
||||||
// Int returns int type.
|
// Int returns int type.
|
||||||
func (p Program) Int() Type {
|
func (p Program) Int() Type {
|
||||||
if p.intTy == nil {
|
if p.intTy == nil {
|
||||||
@@ -160,6 +255,14 @@ func (p Program) Int() Type {
|
|||||||
return p.intTy
|
return p.intTy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Uintptr returns uintptr type.
|
||||||
|
func (p Program) Uintptr() Type {
|
||||||
|
if p.uintptrTy == nil {
|
||||||
|
p.uintptrTy = p.Type(types.Typ[types.Uintptr])
|
||||||
|
}
|
||||||
|
return p.uintptrTy
|
||||||
|
}
|
||||||
|
|
||||||
// Float64 returns float64 type.
|
// Float64 returns float64 type.
|
||||||
func (p Program) Float64() Type {
|
func (p Program) Float64() Type {
|
||||||
if p.f64Ty == nil {
|
if p.f64Ty == nil {
|
||||||
@@ -187,6 +290,7 @@ type aPackage struct {
|
|||||||
|
|
||||||
type Package = *aPackage
|
type Package = *aPackage
|
||||||
|
|
||||||
|
// NewConst creates a new named constant.
|
||||||
func (p Package) NewConst(name string, val constant.Value) NamedConst {
|
func (p Package) NewConst(name string, val constant.Value) NamedConst {
|
||||||
return &aNamedConst{}
|
return &aNamedConst{}
|
||||||
}
|
}
|
||||||
@@ -200,11 +304,19 @@ func (p Package) NewVar(name string, typ types.Type) Global {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VarOf returns a global variable by name.
|
||||||
|
func (p Package) VarOf(name string) Global {
|
||||||
|
return p.vars[name]
|
||||||
|
}
|
||||||
|
|
||||||
// NewFunc creates a new function.
|
// NewFunc creates a new function.
|
||||||
func (p Package) NewFunc(name string, sig *types.Signature) Function {
|
func (p Package) NewFunc(name string, sig *types.Signature) Function {
|
||||||
t := p.prog.llvmSignature(sig)
|
if v, ok := p.fns[name]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
t := p.prog.llvmSignature(sig, false)
|
||||||
fn := llvm.AddFunction(p.mod, name, t.ll)
|
fn := llvm.AddFunction(p.mod, name, t.ll)
|
||||||
ret := newFunction(fn, t, p.prog)
|
ret := newFunction(fn, t, p, p.prog)
|
||||||
p.fns[name] = ret
|
p.fns[name] = ret
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
@@ -214,9 +326,10 @@ func (p Package) FuncOf(name string) Function {
|
|||||||
return p.fns[name]
|
return p.fns[name]
|
||||||
}
|
}
|
||||||
|
|
||||||
// VarOf returns a global variable by name.
|
func (p Package) rtFunc(fnName string) Expr {
|
||||||
func (p Package) VarOf(name string) Global {
|
fn := p.prog.runtime().Scope().Lookup(fnName).(*types.Func)
|
||||||
return p.vars[name]
|
name := FullName(fn.Pkg(), fnName)
|
||||||
|
return p.NewFunc(name, fn.Type().(*types.Signature)).Expr
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -23,9 +23,35 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
/*
|
||||||
Initialize(InitAll)
|
func TestMakeInterface(t *testing.T) {
|
||||||
SetDebug(DbgFlagAll)
|
var b Builder
|
||||||
|
b.MakeInterface(types.NewInterfaceType(nil, nil), Expr{}, true).Do(true)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func TestDelayExpr(t *testing.T) {
|
||||||
|
a := delayExprTy(nil)
|
||||||
|
_ = a.String()
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r == nil {
|
||||||
|
t.Log("TestDelayExpr: no error?")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
a.Underlying()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAny(t *testing.T) {
|
||||||
|
prog := NewProgram(nil)
|
||||||
|
prog.SetRuntime(func() *types.Package {
|
||||||
|
ret := types.NewPackage("runtime", "runtime")
|
||||||
|
scope := ret.Scope()
|
||||||
|
name := types.NewTypeName(0, ret, "Interface", nil)
|
||||||
|
types.NewNamed(name, types.NewStruct(nil, nil), nil)
|
||||||
|
scope.Insert(name)
|
||||||
|
return ret
|
||||||
|
})
|
||||||
|
prog.Any()
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertPkg(t *testing.T, p Package, expected string) {
|
func assertPkg(t *testing.T, p Package, expected string) {
|
||||||
@@ -78,6 +104,9 @@ source_filename = "foo/bar"
|
|||||||
|
|
||||||
@a = external global {}
|
@a = external global {}
|
||||||
`)
|
`)
|
||||||
|
if prog.NeedRuntime() {
|
||||||
|
t.Fatal("NeedRuntime?")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNamedStruct(t *testing.T) {
|
func TestNamedStruct(t *testing.T) {
|
||||||
@@ -87,12 +116,15 @@ func TestNamedStruct(t *testing.T) {
|
|||||||
prog := NewProgram(nil)
|
prog := NewProgram(nil)
|
||||||
pkg := prog.NewPackage("bar", "foo/bar")
|
pkg := prog.NewPackage("bar", "foo/bar")
|
||||||
pkg.NewVar("a", empty)
|
pkg.NewVar("a", empty)
|
||||||
|
if pkg.VarOf("a") == nil {
|
||||||
|
t.Fatal("VarOf failed")
|
||||||
|
}
|
||||||
assertPkg(t, pkg, `; ModuleID = 'foo/bar'
|
assertPkg(t, pkg, `; ModuleID = 'foo/bar'
|
||||||
source_filename = "foo/bar"
|
source_filename = "foo/bar"
|
||||||
|
|
||||||
%Empty = type {}
|
%bar.Empty = type {}
|
||||||
|
|
||||||
@a = external global %Empty
|
@a = external global %bar.Empty
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,6 +134,12 @@ func TestDeclFunc(t *testing.T) {
|
|||||||
params := types.NewTuple(types.NewVar(0, nil, "a", types.Typ[types.Int]))
|
params := types.NewTuple(types.NewVar(0, nil, "a", types.Typ[types.Int]))
|
||||||
sig := types.NewSignatureType(nil, nil, nil, params, nil, false)
|
sig := types.NewSignatureType(nil, nil, nil, params, nil, false)
|
||||||
pkg.NewFunc("fn", sig)
|
pkg.NewFunc("fn", sig)
|
||||||
|
if pkg.FuncOf("fn") == nil {
|
||||||
|
t.Fatal("FuncOf failed")
|
||||||
|
}
|
||||||
|
if prog.retType(sig) != prog.Void() {
|
||||||
|
t.Fatal("retType failed")
|
||||||
|
}
|
||||||
assertPkg(t, pkg, `; ModuleID = 'foo/bar'
|
assertPkg(t, pkg, `; ModuleID = 'foo/bar'
|
||||||
source_filename = "foo/bar"
|
source_filename = "foo/bar"
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,14 @@ func (b Builder) SetBlock(blk BasicBlock) Builder {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Panic emits a panic instruction.
|
||||||
|
func (b Builder) Panic(v Expr) {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("Panic %v\n", v.impl)
|
||||||
|
}
|
||||||
|
b.impl.CreateUnreachable() // TODO(xsw): pass v
|
||||||
|
}
|
||||||
|
|
||||||
// Return emits a return instruction.
|
// Return emits a return instruction.
|
||||||
func (b Builder) Return(results ...Expr) {
|
func (b Builder) Return(results ...Expr) {
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
|
|||||||
80
ssa/type.go
80
ssa/type.go
@@ -17,12 +17,16 @@
|
|||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"go/types"
|
"go/types"
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/goplus/llvm"
|
"github.com/goplus/llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
tyAny = types.NewInterfaceType(nil, nil)
|
||||||
|
)
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
type valueKind = int
|
type valueKind = int
|
||||||
@@ -35,8 +39,10 @@ const (
|
|||||||
vkComplex
|
vkComplex
|
||||||
vkString
|
vkString
|
||||||
vkBool
|
vkBool
|
||||||
|
vkPtr
|
||||||
vkFunc
|
vkFunc
|
||||||
vkTuple
|
vkTuple
|
||||||
|
vkDelayExpr = -1
|
||||||
)
|
)
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@@ -72,6 +78,22 @@ func indexType(t types.Type) types.Type {
|
|||||||
panic("index: type doesn't support index - " + t.String())
|
panic("index: type doesn't support index - " + t.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// convert method to func
|
||||||
|
func methodToFunc(sig *types.Signature) *types.Signature {
|
||||||
|
if recv := sig.Recv(); recv != nil {
|
||||||
|
tParams := sig.Params()
|
||||||
|
nParams := tParams.Len()
|
||||||
|
params := make([]*types.Var, nParams+1)
|
||||||
|
params[0] = recv
|
||||||
|
for i := 0; i < nParams; i++ {
|
||||||
|
params[i+1] = tParams.At(i)
|
||||||
|
}
|
||||||
|
return types.NewSignatureType(
|
||||||
|
nil, nil, nil, types.NewTuple(params...), sig.Results(), sig.Variadic())
|
||||||
|
}
|
||||||
|
return sig
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
type aType struct {
|
type aType struct {
|
||||||
@@ -95,7 +117,15 @@ func (p Program) Index(typ Type) Type {
|
|||||||
return p.Type(indexType(typ.t))
|
return p.Type(indexType(typ.t))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p Program) Field(typ Type, i int) Type {
|
||||||
|
tunder := typ.t.Underlying()
|
||||||
|
return p.Type(tunder.(*types.Struct).Field(i).Type())
|
||||||
|
}
|
||||||
|
|
||||||
func (p Program) Type(typ types.Type) Type {
|
func (p Program) Type(typ types.Type) Type {
|
||||||
|
if sig, ok := typ.(*types.Signature); ok { // should methodToFunc
|
||||||
|
return p.llvmSignature(sig, true)
|
||||||
|
}
|
||||||
if v := p.typs.At(typ); v != nil {
|
if v := p.typs.At(typ); v != nil {
|
||||||
return v.(Type)
|
return v.(Type)
|
||||||
}
|
}
|
||||||
@@ -104,11 +134,12 @@ func (p Program) Type(typ types.Type) Type {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Program) llvmSignature(sig *types.Signature) Type {
|
func (p Program) llvmSignature(sig *types.Signature, isPtr bool) Type {
|
||||||
|
sig = methodToFunc(sig)
|
||||||
if v := p.typs.At(sig); v != nil {
|
if v := p.typs.At(sig); v != nil {
|
||||||
return v.(Type)
|
return v.(Type)
|
||||||
}
|
}
|
||||||
ret := p.toLLVMFunc(sig)
|
ret := p.toLLVMFunc(sig, isPtr)
|
||||||
p.typs.Set(sig, ret)
|
p.typs.Set(sig, ret)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
@@ -209,27 +240,28 @@ func (p Program) toLLVMType(typ types.Type) Type {
|
|||||||
case types.Complex64:
|
case types.Complex64:
|
||||||
case types.Complex128:
|
case types.Complex128:
|
||||||
case types.String:
|
case types.String:
|
||||||
|
return &aType{p.rtString(), typ, vkString}
|
||||||
case types.UnsafePointer:
|
case types.UnsafePointer:
|
||||||
return &aType{p.tyVoidPtr(), typ, vkInvalid}
|
return &aType{p.tyVoidPtr(), typ, vkPtr}
|
||||||
}
|
}
|
||||||
case *types.Pointer:
|
case *types.Pointer:
|
||||||
elem := p.Type(t.Elem())
|
elem := p.Type(t.Elem())
|
||||||
return &aType{llvm.PointerType(elem.ll, 0), typ, vkInvalid}
|
return &aType{llvm.PointerType(elem.ll, 0), typ, vkPtr}
|
||||||
|
case *types.Interface:
|
||||||
|
return &aType{p.rtIface(), typ, vkInvalid}
|
||||||
case *types.Slice:
|
case *types.Slice:
|
||||||
|
return &aType{p.rtSlice(), typ, vkInvalid}
|
||||||
case *types.Map:
|
case *types.Map:
|
||||||
case *types.Struct:
|
case *types.Struct:
|
||||||
return p.toLLVMStruct(t)
|
return p.toLLVMStruct(t)
|
||||||
case *types.Named:
|
case *types.Named:
|
||||||
return p.toLLVMNamed(t)
|
return p.toLLVMNamed(t)
|
||||||
case *types.Signature:
|
|
||||||
return p.toLLVMFunc(t)
|
|
||||||
case *types.Array:
|
case *types.Array:
|
||||||
elem := p.Type(t.Elem())
|
elem := p.Type(t.Elem())
|
||||||
return &aType{llvm.ArrayType(elem.ll, int(t.Len())), typ, vkInvalid}
|
return &aType{llvm.ArrayType(elem.ll, int(t.Len())), typ, vkInvalid}
|
||||||
case *types.Chan:
|
case *types.Chan:
|
||||||
}
|
}
|
||||||
log.Println("toLLVMType: todo -", typ)
|
panic(fmt.Sprintf("toLLVMType: todo - %T\n", typ))
|
||||||
panic("todo")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Program) toLLVMNamedStruct(name string, typ *types.Struct) llvm.Type {
|
func (p Program) toLLVMNamedStruct(name string, typ *types.Struct) llvm.Type {
|
||||||
@@ -269,7 +301,7 @@ func (p Program) toLLVMTypes(t *types.Tuple, n int) (ret []llvm.Type) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Program) toLLVMFunc(sig *types.Signature) Type {
|
func (p Program) toLLVMFunc(sig *types.Signature, isPtr bool) Type {
|
||||||
tParams := sig.Params()
|
tParams := sig.Params()
|
||||||
n := tParams.Len()
|
n := tParams.Len()
|
||||||
hasVArg := HasVArg(tParams, n)
|
hasVArg := HasVArg(tParams, n)
|
||||||
@@ -288,6 +320,9 @@ func (p Program) toLLVMFunc(sig *types.Signature) Type {
|
|||||||
ret = p.toLLVMTuple(out)
|
ret = p.toLLVMTuple(out)
|
||||||
}
|
}
|
||||||
ft := llvm.FunctionType(ret, params, hasVArg)
|
ft := llvm.FunctionType(ret, params, hasVArg)
|
||||||
|
if isPtr {
|
||||||
|
ft = llvm.PointerType(ft, 0)
|
||||||
|
}
|
||||||
return &aType{ft, sig, vkFunc}
|
return &aType{ft, sig, vkFunc}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,12 +339,29 @@ func (p Program) retType(sig *types.Signature) Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p Program) toLLVMNamed(typ *types.Named) Type {
|
func (p Program) toLLVMNamed(typ *types.Named) Type {
|
||||||
name := typ.Obj().Name()
|
switch t := typ.Underlying().(type) {
|
||||||
switch typ := typ.Underlying().(type) {
|
|
||||||
case *types.Struct:
|
case *types.Struct:
|
||||||
return &aType{p.toLLVMNamedStruct(name, typ), typ, vkInvalid}
|
name := NameOf(typ)
|
||||||
|
return &aType{p.toLLVMNamedStruct(name, t), typ, vkInvalid}
|
||||||
|
default:
|
||||||
|
return p.Type(t)
|
||||||
}
|
}
|
||||||
panic("todo")
|
}
|
||||||
|
|
||||||
|
func NameOf(typ *types.Named) string {
|
||||||
|
obj := typ.Obj()
|
||||||
|
return FullName(obj.Pkg(), obj.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
func FullName(pkg *types.Package, name string) string {
|
||||||
|
return PathOf(pkg) + "." + name
|
||||||
|
}
|
||||||
|
|
||||||
|
func PathOf(pkg *types.Package) string {
|
||||||
|
if pkg.Name() == "main" {
|
||||||
|
return "main"
|
||||||
|
}
|
||||||
|
return pkg.Path()
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2023 The GoPlus Authors (goplus.org). All rights reserved.
|
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -14,24 +14,37 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package llgo
|
package clang
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/x/gocmd"
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
func BuildDir(dir string, conf *Config, build *gocmd.BuildConfig) (err error) {
|
// Cmd represents a nm command.
|
||||||
panic("todo")
|
type Cmd struct {
|
||||||
|
app string
|
||||||
|
|
||||||
|
Stdout io.Writer
|
||||||
|
Stderr io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildPkgPath(workDir, pkgPath string, conf *Config, build *gocmd.BuildConfig) (err error) {
|
// New creates a new nm command.
|
||||||
panic("todo")
|
func New(app string) *Cmd {
|
||||||
|
if app == "" {
|
||||||
|
app = "clang"
|
||||||
|
}
|
||||||
|
return &Cmd{app, os.Stdout, os.Stderr}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildFiles(files []string, conf *Config, build *gocmd.BuildConfig) (err error) {
|
func (p *Cmd) Exec(args ...string) error {
|
||||||
panic("todo")
|
cmd := exec.Command(p.app, args...)
|
||||||
|
cmd.Stdout = p.Stdout
|
||||||
|
cmd.Stderr = p.Stderr
|
||||||
|
return cmd.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 llexportdata
|
|
||||||
|
|
||||||
import (
|
|
||||||
"go/token"
|
|
||||||
"go/types"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Read reads export data from in, decodes it, and returns type information for the package.
|
|
||||||
//
|
|
||||||
// The package path (effectively its linker symbol prefix) is specified by path, since unlike
|
|
||||||
// the package name, this information may not be recorded in the export data.
|
|
||||||
//
|
|
||||||
// File position information is added to fset.
|
|
||||||
//
|
|
||||||
// Read may inspect and add to the imports map to ensure that references within the export data
|
|
||||||
// to other packages are consistent. The caller must ensure that imports[path] does not exist,
|
|
||||||
// or exists but is incomplete (see types.Package.Complete), and Read inserts the resulting package
|
|
||||||
// into this map entry.
|
|
||||||
//
|
|
||||||
// On return, the state of the reader is undefined.
|
|
||||||
func Read(in io.Reader, fset *token.FileSet, imports map[string]*types.Package, path string) (*types.Package, error) {
|
|
||||||
panic("todo")
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user