Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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"
|
||||||
8
.github/workflows/go.yml
vendored
8
.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'
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ 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://github.com/goplus/llgo/releases)
|
||||||
[](https://pkg.go.dev/github.com/goplus/llgo)
|
[](https://pkg.go.dev/github.com/goplus/llgo)
|
||||||
<!--
|
<!--
|
||||||
[](https://github.com/goplus/llgo/releases)
|
|
||||||
[](https://codecov.io/gh/goplus/llgo)
|
[](https://codecov.io/gh/goplus/llgo)
|
||||||
-->
|
-->
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -21,12 +21,12 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"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 xxx.go [pkgPath]")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,6 +35,13 @@ func main() {
|
|||||||
dir, _ := filepath.Split(inFile)
|
dir, _ := filepath.Split(inFile)
|
||||||
outFile := dir + "out.ll"
|
outFile := dir + "out.ll"
|
||||||
|
|
||||||
|
pkgPath := ""
|
||||||
|
if len(os.Args) == 3 {
|
||||||
|
pkgPath = os.Args[2]
|
||||||
|
} else {
|
||||||
|
pkgPath = llgen.PkgPath(dir)
|
||||||
|
}
|
||||||
|
|
||||||
llgen.Init()
|
llgen.Init()
|
||||||
llgen.Do(inFile, outFile)
|
llgen.Do(pkgPath, inFile, outFile)
|
||||||
}
|
}
|
||||||
|
|||||||
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 }
|
||||||
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 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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -1,22 +1,22 @@
|
|||||||
; 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 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
|
||||||
@@ -30,7 +30,7 @@ _llgo_2: ; preds = %_llgo_0
|
|||||||
|
|
||||||
define void @main() {
|
define void @main() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
call void @init()
|
call void @main.init()
|
||||||
%0 = call i64 @max(i64 1, i64 2)
|
%0 = call i64 @main.max(i64 1, i64 2)
|
||||||
ret void
|
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.init$guard" = global ptr null
|
||||||
|
@main.hello = 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, ...)
|
||||||
@@ -2,7 +2,7 @@ package main
|
|||||||
|
|
||||||
import _ "unsafe"
|
import _ "unsafe"
|
||||||
|
|
||||||
//go:linkname printf _printf
|
//go:linkname printf 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,23 +1,23 @@
|
|||||||
; ModuleID = 'main'
|
; ModuleID = 'main'
|
||||||
source_filename = "main"
|
source_filename = "main"
|
||||||
|
|
||||||
@"init$guard" = global ptr null
|
@"main.init$guard" = global ptr null
|
||||||
@hello = global ptr null
|
@main.hello = 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
|
||||||
@@ -28,7 +28,7 @@ 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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
; ModuleID = 'main'
|
; ModuleID = 'main'
|
||||||
source_filename = "main"
|
source_filename = "main"
|
||||||
|
|
||||||
@"init$guard" = global ptr null
|
@"main.init$guard" = global ptr null
|
||||||
@a = global ptr null
|
@main.a = 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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ package cl
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
@@ -57,14 +60,15 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
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" && fn.Pkg.Pkg.Path() == "unsafe" {
|
||||||
return fnUnsafeInit
|
return fnUnsafeInit
|
||||||
}
|
}
|
||||||
} 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,12 +77,10 @@ func funcKind(vfn ssa.Value) int {
|
|||||||
return fnNormal
|
return fnNormal
|
||||||
}
|
}
|
||||||
|
|
||||||
func isMainFunc(fn *ssa.Function) bool {
|
|
||||||
return fn.Name() == "main" && fn.Pkg.Pkg.Path() == "main"
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type none = struct{}
|
||||||
|
|
||||||
type instrAndValue interface {
|
type instrAndValue interface {
|
||||||
ssa.Instruction
|
ssa.Instruction
|
||||||
ssa.Value
|
ssa.Value
|
||||||
@@ -88,7 +90,11 @@ type context struct {
|
|||||||
prog llssa.Program
|
prog llssa.Program
|
||||||
pkg llssa.Package
|
pkg llssa.Package
|
||||||
fn llssa.Function
|
fn llssa.Function
|
||||||
|
fset *token.FileSet
|
||||||
|
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
|
||||||
inits []func()
|
inits []func()
|
||||||
}
|
}
|
||||||
@@ -99,7 +105,8 @@ func (p *context) compileType(pkg llssa.Package, member *ssa.Type) {
|
|||||||
|
|
||||||
// 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 := fullName(gbl.Pkg.Pkg, gbl.Name())
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
log.Println("==> NewVar", name, typ)
|
log.Println("==> NewVar", name, typ)
|
||||||
}
|
}
|
||||||
@@ -108,7 +115,10 @@ func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) compileFunc(pkg llssa.Package, f *ssa.Function) {
|
func (p *context) compileFunc(pkg llssa.Package, f *ssa.Function) {
|
||||||
name := f.Name()
|
name := p.funcName(f.Pkg.Pkg, f)
|
||||||
|
if name == "unsafe.init" {
|
||||||
|
return
|
||||||
|
}
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
log.Println("==> NewFunc", name)
|
log.Println("==> NewFunc", name)
|
||||||
}
|
}
|
||||||
@@ -130,9 +140,8 @@ 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)
|
|
||||||
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")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -142,7 +151,7 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, doInit bo
|
|||||||
b.SetBlock(ret)
|
b.SetBlock(ret)
|
||||||
p.bvals = make(map[ssa.Value]llssa.Expr)
|
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 {
|
||||||
@@ -238,16 +247,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()
|
||||||
@@ -281,11 +284,8 @@ 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
|
||||||
@@ -305,13 +305,19 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, conf *Config) (ret llssa.P
|
|||||||
})
|
})
|
||||||
|
|
||||||
pkgTypes := pkg.Pkg
|
pkgTypes := pkg.Pkg
|
||||||
ret = prog.NewPackage(pkgTypes.Name(), pkgTypes.Path())
|
pkgName, pkgPath := pkgTypes.Name(), pkgTypes.Path()
|
||||||
|
ret = prog.NewPackage(pkgName, pkgPath)
|
||||||
|
|
||||||
ctx := &context{
|
ctx := &context{
|
||||||
prog: prog,
|
prog: prog,
|
||||||
pkg: ret,
|
pkg: ret,
|
||||||
|
fset: pkg.Prog.Fset,
|
||||||
|
goTyps: pkgTypes,
|
||||||
goPkg: pkg,
|
goPkg: pkg,
|
||||||
|
link: make(map[string]string),
|
||||||
|
loaded: make(map[*types.Package]none),
|
||||||
}
|
}
|
||||||
|
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) {
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package cl
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/importer"
|
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
@@ -28,9 +27,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
llssa "github.com/goplus/llgo/ssa"
|
"github.com/goplus/gogen/packages"
|
||||||
"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"
|
||||||
|
|
||||||
|
llssa "github.com/goplus/llgo/ssa"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFromTestdata(t *testing.T) {
|
func TestFromTestdata(t *testing.T) {
|
||||||
@@ -88,14 +89,15 @@ func testCompileEx(t *testing.T, src any, fname, expected string) {
|
|||||||
files := []*ast.File{f}
|
files := []*ast.File{f}
|
||||||
name := f.Name.Name
|
name := f.Name.Name
|
||||||
pkg := types.NewPackage(name, name)
|
pkg := types.NewPackage(name, name)
|
||||||
|
imp := packages.NewImporter(fset)
|
||||||
foo, _, err := ssautil.BuildPackage(
|
foo, _, err := ssautil.BuildPackage(
|
||||||
&types.Config{Importer: importer.Default()}, fset, pkg, files, ssa.SanityCheckFunctions)
|
&types.Config{Importer: imp}, fset, pkg, files, ssa.SanityCheckFunctions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("BuildPackage failed:", err)
|
t.Fatal("BuildPackage failed:", err)
|
||||||
}
|
}
|
||||||
foo.WriteTo(os.Stderr)
|
foo.WriteTo(os.Stderr)
|
||||||
prog := llssa.NewProgram(nil)
|
prog := llssa.NewProgram(nil)
|
||||||
ret, err := NewPackage(prog, foo, nil)
|
ret, err := NewPackage(prog, foo, files)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("cl.NewPackage failed:", err)
|
t.Fatal("cl.NewPackage failed:", err)
|
||||||
}
|
}
|
||||||
@@ -116,16 +118,16 @@ var a int
|
|||||||
`, `; ModuleID = 'foo'
|
`, `; ModuleID = 'foo'
|
||||||
source_filename = "foo"
|
source_filename = "foo"
|
||||||
|
|
||||||
@"init$guard" = global ptr null
|
@"foo.init$guard" = global ptr null
|
||||||
@a = global ptr null
|
@foo.a = 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,22 +145,22 @@ 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 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
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
define i64 @fn(i64 %0, double %1) {
|
define i64 @foo.fn(i64 %0, double %1) {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
ret i64 1
|
ret i64 1
|
||||||
}
|
}
|
||||||
|
|||||||
160
cl/import.go
Normal file
160
cl/import.go
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* 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 := pkg.Path()
|
||||||
|
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 {
|
||||||
|
name := pkgPath + "." + text[:idx]
|
||||||
|
link := strings.TrimLeft(text[idx+1:], " ")
|
||||||
|
p.link[name] = link
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fullName(pkg *types.Package, name string) string {
|
||||||
|
pkgPath := pkg.Name()
|
||||||
|
if pkgPath != "main" {
|
||||||
|
pkgPath = pkg.Path()
|
||||||
|
}
|
||||||
|
return pkgPath + "." + name
|
||||||
|
}
|
||||||
|
|
||||||
|
func funcName(pkg *types.Package, fn *ssa.Function) string {
|
||||||
|
ret := fullName(pkg, fn.Name())
|
||||||
|
if ret == "main.main" {
|
||||||
|
ret = "main"
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) funcName(pkg *types.Package, fn *ssa.Function) string {
|
||||||
|
name := funcName(pkg, fn)
|
||||||
|
if v, ok := p.link[name]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) funcOf(fn *ssa.Function) llssa.Function {
|
||||||
|
pkgTypes := p.ensureLoaded(fn.Pkg.Pkg)
|
||||||
|
pkg := p.pkg
|
||||||
|
name := p.funcName(pkgTypes, fn)
|
||||||
|
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 := 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
|
||||||
|
}
|
||||||
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 printf
|
||||||
|
func Printf(format *int8, __llgo_va_list ...any)
|
||||||
|
|
||||||
|
func Max(a, b int) int {
|
||||||
|
if a > b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
@@ -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,27 @@
|
|||||||
* 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)
|
build.Do(args, &build.Config{
|
||||||
if err != nil {
|
Mode: build.ModeBuild,
|
||||||
log.Panicln("parse input arguments failed:", err)
|
AppExt: build.DefaultAppExt(),
|
||||||
}
|
})
|
||||||
|
|
||||||
args = flag.Args()
|
|
||||||
if len(args) == 0 {
|
|
||||||
args = []string{"."}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|||||||
@@ -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,25 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package llgo
|
// Package install implements the "llgo install" command.
|
||||||
|
package install
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
import (
|
||||||
|
"github.com/goplus/llgo/cmd/internal/base"
|
||||||
|
"github.com/goplus/llgo/internal/build"
|
||||||
|
)
|
||||||
|
|
||||||
type Config struct {
|
// 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)
|
||||||
|
}
|
||||||
85
cmd/internal/run/run.go
Normal file
85
cmd/internal/run/run.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 run implements the "llgo run" command.
|
||||||
|
package run
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"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 := parseArgs(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 parseArgs(args []string) int {
|
||||||
|
for i, arg := range args {
|
||||||
|
if !strings.HasPrefix(arg, "-") {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func isGoFile(fname string) bool {
|
||||||
|
return filepath.Ext(fname) == ".go"
|
||||||
|
}
|
||||||
|
|
||||||
|
func check(err error) {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,8 @@ 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/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 +40,8 @@ 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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.1
|
||||||
|
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
|
||||||
)
|
)
|
||||||
|
|||||||
15
go.sum
15
go.sum
@@ -2,12 +2,8 @@ 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.1-0.20240418160956-6233231cbcc9/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 +27,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 +53,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=
|
||||||
|
|||||||
216
internal/build/build.go
Normal file
216
internal/build/build.go
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
"log"
|
||||||
|
"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
|
||||||
|
RunArgs []string
|
||||||
|
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)
|
||||||
|
cfg := &packages.Config{
|
||||||
|
Mode: loadSyntax | packages.NeedDeps | packages.NeedExportFile,
|
||||||
|
BuildFlags: flags,
|
||||||
|
}
|
||||||
|
|
||||||
|
if patterns == nil {
|
||||||
|
patterns = []string{"."}
|
||||||
|
}
|
||||||
|
initial, err := packages.Load(cfg, patterns...)
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
// Create SSA-form program representation.
|
||||||
|
ssaProg, pkgs, errPkgs := allPkgs(initial, ssa.SanityCheckFunctions)
|
||||||
|
ssaProg.Build()
|
||||||
|
for _, errPkg := range errPkgs {
|
||||||
|
log.Println("cannot build SSA for package", errPkg)
|
||||||
|
}
|
||||||
|
|
||||||
|
llssa.Initialize(llssa.InitAll)
|
||||||
|
if verbose {
|
||||||
|
llssa.SetDebug(llssa.DbgFlagAll)
|
||||||
|
cl.SetDebug(cl.DbgFlagAll)
|
||||||
|
}
|
||||||
|
|
||||||
|
prog := llssa.NewProgram(nil)
|
||||||
|
mode := conf.Mode
|
||||||
|
for _, pkg := range pkgs {
|
||||||
|
buildPkg(prog, pkg, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mode != ModeBuild || len(initial) == 1 {
|
||||||
|
for _, pkg := range initial {
|
||||||
|
if pkg.Name == "main" {
|
||||||
|
linkMainPkg(pkg, conf, mode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func linkMainPkg(pkg *packages.Package, conf *Config, mode Mode) {
|
||||||
|
pkgPath := pkg.PkgPath
|
||||||
|
name := path.Base(pkgPath)
|
||||||
|
app := filepath.Join(conf.BinPath, name+conf.AppExt)
|
||||||
|
args := make([]string, 2, len(pkg.Imports)+3)
|
||||||
|
args[0] = "-o"
|
||||||
|
args[1] = app
|
||||||
|
packages.Visit([]*packages.Package{pkg}, nil, func(p *packages.Package) {
|
||||||
|
if p.PkgPath != "unsafe" { // TODO(xsw): remove this special case
|
||||||
|
args = append(args, p.ExportFile+".ll")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO(xsw): show work
|
||||||
|
// fmt.Fprintln(os.Stderr, "clang", args)
|
||||||
|
fmt.Fprintln(os.Stderr, "#", pkgPath)
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildPkg(prog llssa.Program, aPkg aPackage, mode Mode) {
|
||||||
|
pkg := aPkg.Package
|
||||||
|
pkgPath := pkg.PkgPath
|
||||||
|
if mode != ModeRun {
|
||||||
|
fmt.Fprintln(os.Stderr, pkgPath)
|
||||||
|
}
|
||||||
|
if pkgPath == "unsafe" { // TODO(xsw): 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
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseArgs(args []string) (flags, patterns []string, verbose bool) {
|
||||||
|
for i, arg := range args {
|
||||||
|
if !strings.HasPrefix(arg, "-") {
|
||||||
|
flags, patterns = args[:i], args[i:]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if arg == "-v" {
|
||||||
|
verbose = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flags = args
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func check(err error) {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
@@ -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()
|
||||||
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")
|
||||||
|
)
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
@@ -230,7 +230,7 @@ func (b Builder) BinOp(op token.Token, x, y Expr) Expr {
|
|||||||
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")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,6 +87,9 @@ 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"
|
||||||
|
|
||||||
@@ -102,6 +105,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"
|
||||||
|
|
||||||
|
|||||||
@@ -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,33 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package llgo
|
package clang
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goplus/llgo/x/gocmd"
|
"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
|
||||||
}
|
}
|
||||||
|
|
||||||
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}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = os.Stdout
|
||||||
|
cmd.Stderr = os.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