Compare commits

..

64 Commits

Author SHA1 Message Date
xushiwei
aa1d0b307b Merge pull request #90 from xushiwei/q
llvm v0.7.3
2024-05-01 18:15:05 +08:00
xushiwei
8a09d8b442 update llvm 2024-05-01 18:12:42 +08:00
xushiwei
7b99470bfa llvm v0.7.3 2024-05-01 18:11:58 +08:00
xushiwei
30192da7cf Merge pull request #89 from xushiwei/q
build: make empty runtime.init if no runtime needed
2024-05-01 17:45:55 +08:00
xushiwei
66337e0975 build: make empty runtime.init if no runtime needed 2024-05-01 17:44:12 +08:00
xushiwei
6e4a44438b Merge pull request #88 from xushiwei/q
llgo/ssa: builder.Alloc sizeof(t) bugfix
2024-05-01 17:01:51 +08:00
xushiwei
3cc3b864af fix Alloc size 2024-05-01 16:59:42 +08:00
xushiwei
62f6542ca9 llgo/ssa: builder.Alloc sizeof(t) bugfix 2024-05-01 16:56:26 +08:00
xushiwei
8c25848e1b Merge pull request #87 from xushiwei/q
cl: callRuntimeInit; runtime: TracePanic; cl: _testrt/gblarray (todo)
2024-05-01 16:10:09 +08:00
xushiwei
e112d8277f cl: _testrt/gblarray 2024-05-01 16:06:49 +08:00
xushiwei
014d0262da build: fix link runtime multiple times 2024-05-01 13:30:13 +08:00
xushiwei
8ae97f73d0 debug why runtime.Basic doesn't work 2024-05-01 12:32:09 +08:00
xushiwei
666808b427 cl: callRuntimeInit; runtime: TracePanic 2024-05-01 11:03:52 +08:00
xushiwei
f208db48a1 Merge pull request #86 from xushiwei/q
runtime: MakeSmallMap
2024-05-01 07:40:24 +08:00
xushiwei
673b9d9a5c runtime.MakeSmallMap 2024-05-01 07:37:38 +08:00
xushiwei
ed8ffb228b runtime: MakeMap 2024-05-01 07:26:51 +08:00
xushiwei
d5a3ff6fb9 Merge pull request #85 from xushiwei/q
llgo/ssa: allocaCStr; runtime: String
2024-04-30 23:21:49 +08:00
xushiwei
d3fddfb634 mv _testcgo => _testrt 2024-04-30 23:18:18 +08:00
xushiwei
f7a54e3377 llgo/ssa: builder.Str bugfix; runtime: NewString 2024-04-30 18:42:40 +08:00
xushiwei
d62bf858dd llgo/ssa: Go const string 2024-04-30 18:37:31 +08:00
xushiwei
ae0906d322 llgo/ssa: allocaCStr; runtime: String 2024-04-30 18:22:56 +08:00
xushiwei
c6cb2931e1 Merge pull request #84 from xushiwei/q
llgo/ssa: Slice, IndexAddr bugfix
2024-04-30 16:22:01 +08:00
xushiwei
0eac576171 Merge pull request #83 from visualfc/error
build: buildAllPkgs dump error
2024-04-30 16:21:09 +08:00
xushiwei
0ee96db260 IndexAddr: default as ptr 2024-04-30 16:19:25 +08:00
xushiwei
40a9e00d4c llgo/ssa: Slice, IndexAddr bugfix 2024-04-30 16:15:36 +08:00
visualfc
d8615330ad build: buildAllPkgs dump error 2024-04-30 15:58:01 +08:00
xushiwei
02afd1d73a Merge pull request #82 from visualfc/slice
ssa: fix newSlice.type & const
2024-04-30 14:33:12 +08:00
visualfc
4eedb4fb69 cltest: SetRuntime 2024-04-30 14:16:46 +08:00
visualfc
2d6869bdbd ssa: fix newSlice.type & const 2024-04-30 14:14:28 +08:00
xushiwei
c0a9848cfb Merge pull request #81 from xushiwei/q
llgo/ssa,runtime: Slice; llgo/ssa: phi node
2024-04-30 11:36:11 +08:00
xushiwei
40cc7b2a85 llgen runtime 2024-04-30 11:31:39 +08:00
xushiwei
dfaae24fea update llvm 2024-04-30 11:26:40 +08:00
xushiwei
839ad8ba2b cl: _testcgo/sum 2024-04-30 11:19:42 +08:00
xushiwei
e757c66354 llgo/ssa: phi node 2024-04-30 10:34:10 +08:00
xushiwei
3ec6da002a Merge remote-tracking branch 'gop/main' into q 2024-04-30 08:27:57 +08:00
xushiwei
190b029154 Merge pull request #80 from visualfc/const
cl: compileValue check types.Default for const
2024-04-30 08:26:23 +08:00
xushiwei
0bfc269652 llgo/ssa,runtime: Slice 2024-04-30 08:23:55 +08:00
visualfc
b5961f0807 cl/_testdata: add untyped test 2024-04-30 08:14:08 +08:00
visualfc
a792e312db cl: compileValue check types.Default for const 2024-04-30 08:13:39 +08:00
xushiwei
04f81f3dbb Merge pull request #79 from xushiwei/q
ignore .DS_Store
2024-04-29 23:43:03 +08:00
xushiwei
91401c4571 ignore .DS_Store 2024-04-29 23:42:37 +08:00
xushiwei
18fe26e853 Merge pull request #77 from visualfc/float
ssa: builder.const add float
2024-04-29 23:09:22 +08:00
xushiwei
f895ca1fe6 Merge pull request #78 from xushiwei/q
llgo/ssa: MakeInterface
2024-04-29 23:04:59 +08:00
xushiwei
ad28ed3154 cl: _testcgo/any 2024-04-29 22:58:25 +08:00
xushiwei
f64abf37ab llgo/ssa: MakeInterface 2024-04-29 22:57:40 +08:00
visualfc
acc5de8d14 ssa: builder.const add float 2024-04-29 22:19:08 +08:00
xushiwei
85bb1302ca Merge pull request #76 from xushiwei/q
llgen bugfix
2024-04-29 20:52:58 +08:00
xushiwei
fc893ba498 llgen bugfix 2024-04-29 20:51:27 +08:00
xushiwei
7527b326d7 Merge pull request #75 from xushiwei/q
cl: support llgo.cstr
2024-04-29 19:01:01 +08:00
xushiwei
a6d31ad8b8 TestErrAlloca 2024-04-29 18:55:09 +08:00
xushiwei
664c3fcce3 compileInstrOrValue 2024-04-29 18:46:13 +08:00
xushiwei
e1d1d6a2d9 llgo/ssa: unreachable 2024-04-29 18:33:02 +08:00
xushiwei
8c1b8ad945 update llvm 2024-04-29 18:12:15 +08:00
xushiwei
ae5efdf16c disable ArrayAlloca 2024-04-29 18:01:03 +08:00
xushiwei
2b82af519c llgo/ssa: Alloca, ArrayAlloca 2024-04-29 17:58:10 +08:00
xushiwei
7a347d4563 update llvm 2024-04-29 14:39:37 +08:00
xushiwei
1610894a80 llgo/ssa: b.CString 2024-04-29 14:34:26 +08:00
xushiwei
4eb2ddaf15 cl: support llgo.cstr 2024-04-29 13:59:06 +08:00
xushiwei
99a86d8d4e Merge pull request #74 from xushiwei/q
build: skip PkgDeclOnly; cl: skip init if PkgNoInit
2024-04-29 12:04:07 +08:00
xushiwei
637db665c3 TestPkgKindOf 2024-04-29 11:58:48 +08:00
xushiwei
bb1da81a01 build: skip PkgDeclOnly 2024-04-29 11:34:59 +08:00
xushiwei
d4ddc61a9f cl: TestPkgNoInit/TestPkgKind 2024-04-29 10:06:47 +08:00
xushiwei
6ebbc92c4f runtime.ll 2024-04-29 09:53:48 +08:00
xushiwei
b45172bef1 cl: pkgKind = normal/noinit/decl 2024-04-29 09:51:32 +08:00
69 changed files with 3605 additions and 279 deletions

1
.gitignore vendored
View File

@@ -8,6 +8,7 @@
*.so *.so
*.dylib *.dylib
.DS_Store
err.log err.log
_go/ _go/

View File

@@ -0,0 +1,57 @@
/*
* 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 main
import (
"fmt"
"os"
"strings"
"github.com/goplus/llgo/internal/llgen"
"github.com/goplus/mod"
)
func main() {
dir, _, err := mod.FindGoMod(".")
check(err)
llgen.Verbose = false
llgenDir(dir + "/cl/_testrt")
llgenDir(dir+"/cl/_testdata", "")
}
func llgenDir(dir string, pkgPath ...string) {
fis, err := os.ReadDir(dir)
check(err)
for _, fi := range fis {
name := fi.Name()
if !fi.IsDir() || strings.HasPrefix(name, "_") {
continue
}
testDir := dir + "/" + name
fmt.Fprintln(os.Stderr, "llgen", testDir)
os.Chdir(testDir)
llgen.SmartDoFile("in.go", pkgPath...)
}
}
func check(err error) {
if err != nil {
panic(err)
}
}

View File

@@ -19,8 +19,6 @@ package main
import ( import (
"fmt" "fmt"
"os" "os"
"path/filepath"
"strings"
"github.com/goplus/llgo/internal/llgen" "github.com/goplus/llgo/internal/llgen"
) )
@@ -31,24 +29,6 @@ func main() {
return return
} }
inFile := os.Args[1]
dir, _ := filepath.Split(inFile)
fname := "llgo_autogen.ll"
if inCompilerDir(dir) {
fname = "out.ll"
}
outFile := dir + fname
llgen.Init() llgen.Init()
if len(os.Args) >= 3 { llgen.SmartDoFile(os.Args[1], os.Args[2:]...)
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/")
} }

View File

@@ -1,16 +0,0 @@
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))
}

View File

@@ -18,6 +18,7 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
define void @main() { define void @main() {
_llgo_0: _llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init() call void @main.init()
%0 = call i64 @main.max(i64 1, i64 2) %0 = call i64 @main.max(i64 1, i64 2)
ret void ret void
@@ -34,3 +35,5 @@ _llgo_1: ; preds = %_llgo_0
_llgo_2: ; preds = %_llgo_0 _llgo_2: ; preds = %_llgo_0
ret i64 %1 ret i64 %1
} }
declare void @"github.com/goplus/llgo/internal/runtime.init"()

View File

@@ -27,6 +27,7 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
define void @main() { define void @main() {
_llgo_0: _llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init() call void @main.init()
%0 = call i64 @"github.com/goplus/llgo/cl/internal/stdio.Max"(i64 2, i64 100) %0 = call i64 @"github.com/goplus/llgo/cl/internal/stdio.Max"(i64 2, i64 100)
call void (ptr, ...) @printf(ptr @main.hello) call void (ptr, ...) @printf(ptr @main.hello)
@@ -35,6 +36,8 @@ _llgo_0:
declare void @"github.com/goplus/llgo/cl/internal/stdio.init"() declare void @"github.com/goplus/llgo/cl/internal/stdio.init"()
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare i64 @"github.com/goplus/llgo/cl/internal/stdio.Max"(i64, i64) declare i64 @"github.com/goplus/llgo/cl/internal/stdio.Max"(i64, i64)
declare void @printf(ptr, ...) declare void @printf(ptr, ...)

View File

@@ -42,6 +42,7 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
define void @main() { define void @main() {
_llgo_0: _llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init() call void @main.init()
%0 = call i64 @"(main.T).Add"(i64 1, i64 2) %0 = call i64 @"(main.T).Add"(i64 1, i64 2)
call void (ptr, ...) @printf(ptr @main.format, i64 %0) call void (ptr, ...) @printf(ptr @main.format, i64 %0)
@@ -49,3 +50,5 @@ _llgo_0:
} }
declare void @printf(ptr, ...) declare void @printf(ptr, ...)
declare void @"github.com/goplus/llgo/internal/runtime.init"()

View File

@@ -26,9 +26,12 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
define void @main() { define void @main() {
_llgo_0: _llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init() call void @main.init()
call void (ptr, ...) @printf(ptr @main.hello) call void (ptr, ...) @printf(ptr @main.hello)
ret void ret void
} }
declare void @printf(ptr, ...) declare void @printf(ptr, ...)
declare void @"github.com/goplus/llgo/internal/runtime.init"()

View File

@@ -29,9 +29,12 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
define void @main() { define void @main() {
_llgo_0: _llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init() call void @main.init()
call void (ptr, ...) @printf(ptr @main.format, i64 100) call void (ptr, ...) @printf(ptr @main.format, i64 100)
ret void ret void
} }
declare void @printf(ptr, ...) declare void @printf(ptr, ...)
declare void @"github.com/goplus/llgo/internal/runtime.init"()

View File

@@ -35,9 +35,12 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
define void @main() { define void @main() {
_llgo_0: _llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init() call void @main.init()
call void @"(*main.T).Print"(ptr @main.format, i64 100) call void @"(*main.T).Print"(ptr @main.format, i64 100)
ret void ret void
} }
declare void @printf(ptr, ...) declare void @printf(ptr, ...)
declare void @"github.com/goplus/llgo/internal/runtime.init"()

View File

@@ -0,0 +1,11 @@
package main
const c = 100
var a float64 = 1
func main() {
if c > 100 {
a = 0
}
}

View File

@@ -0,0 +1,35 @@
; ModuleID = 'main'
source_filename = "main"
@main.a = 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 double 1.000000e+00, ptr @main.a, align 8
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
define void @main() {
_llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init()
br i1 false, label %_llgo_1, label %_llgo_2
_llgo_1: ; preds = %_llgo_0
store double 0.000000e+00, ptr @main.a, align 8
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
declare void @"github.com/goplus/llgo/internal/runtime.init"()

View File

@@ -20,6 +20,7 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
define void @main() { define void @main() {
_llgo_0: _llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init() call void @main.init()
%0 = load i64, ptr @main.a, align 4 %0 = load i64, ptr @main.a, align 4
%1 = add i64 %0, 1 %1 = add i64 %0, 1
@@ -27,3 +28,5 @@ _llgo_0:
%2 = load i64, ptr @main.a, align 4 %2 = load i64, ptr @main.a, align 4
ret void ret void
} }
declare void @"github.com/goplus/llgo/internal/runtime.init"()

12
cl/_testrt/alloca/in.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import (
"github.com/goplus/llgo/internal/runtime/c"
)
func main() {
s := c.Str("Hi\n")
s2 := c.Alloca(4)
c.Memcpy(s2, c.Pointer(s), 4)
c.Printf(c.Str("%s"), s2)
}

35
cl/_testrt/alloca/out.ll Normal file
View File

@@ -0,0 +1,35 @@
; ModuleID = 'main'
source_filename = "main"
@"main.init$guard" = global ptr null
@0 = private unnamed_addr constant [4 x i8] c"Hi\0A\00", align 1
@1 = private unnamed_addr constant [3 x i8] c"%s\00", align 1
define void @main.init() {
_llgo_0:
%0 = load i1, ptr @"main.init$guard", align 1
br i1 %0, label %_llgo_2, label %_llgo_1
_llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
define void @main() {
_llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init()
%0 = alloca i8, i64 4, align 1
%1 = call ptr @memcpy(ptr %0, ptr @0, i64 4)
%2 = call i32 (ptr, ...) @printf(ptr @1, ptr %0)
ret void
}
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare ptr @memcpy(ptr, ptr, i64)
declare i32 @printf(ptr, ...)

13
cl/_testrt/allocstr/in.go Normal file
View File

@@ -0,0 +1,13 @@
package main
import (
"github.com/goplus/llgo/internal/runtime/c"
)
func hello() string {
return "Hello world\n"
}
func main() {
c.Printf(c.AllocaCStr(hello()))
}

View File

@@ -0,0 +1,50 @@
; ModuleID = 'main'
source_filename = "main"
%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 }
%"github.com/goplus/llgo/internal/runtime.Slice" = type { ptr, i64, i64 }
@"main.init$guard" = global ptr null
@0 = private unnamed_addr constant [13 x i8] c"Hello world\0A\00", align 1
define %"github.com/goplus/llgo/internal/runtime.String" @main.hello() {
_llgo_0:
%0 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @0, i64 12)
ret %"github.com/goplus/llgo/internal/runtime.String" %0
}
define void @main.init() {
_llgo_0:
%0 = load i1, ptr @"main.init$guard", align 1
br i1 %0, label %_llgo_2, label %_llgo_1
_llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
define void @main() {
_llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init()
%0 = call %"github.com/goplus/llgo/internal/runtime.String" @main.hello()
%1 = call i64 @"github.com/goplus/llgo/internal/runtime.StringLen"(%"github.com/goplus/llgo/internal/runtime.String" %0)
%2 = add i64 %1, 1
%3 = alloca i8, i64 %2, align 1
%4 = call ptr @"github.com/goplus/llgo/internal/runtime.CStrCopy"(ptr %3, %"github.com/goplus/llgo/internal/runtime.String" %0)
%5 = call i32 (ptr, ...) @printf(ptr %4)
ret void
}
declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr, i64)
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare i64 @"github.com/goplus/llgo/internal/runtime.StringLen"(%"github.com/goplus/llgo/internal/runtime.Slice")
declare ptr @"github.com/goplus/llgo/internal/runtime.CStrCopy"(ptr, %"github.com/goplus/llgo/internal/runtime.String")
declare i32 @printf(ptr, ...)

13
cl/_testrt/any/in.go Normal file
View File

@@ -0,0 +1,13 @@
package main
import (
"github.com/goplus/llgo/internal/runtime/c"
)
func incVal(a any) int {
return a.(int) + 1
}
func main() {
c.Printf(c.Str("Hello %d\n"), incVal(100))
}

View File

@@ -3,8 +3,8 @@ source_filename = "main"
%"github.com/goplus/llgo/internal/runtime.iface" = type { ptr, ptr } %"github.com/goplus/llgo/internal/runtime.iface" = type { ptr, ptr }
@main.format = global ptr null
@"main.init$guard" = global ptr null @"main.init$guard" = global ptr null
@0 = private unnamed_addr constant [10 x i8] c"Hello %d\0A\00", align 1
define i64 @main.incVal(%"github.com/goplus/llgo/internal/runtime.iface" %0) { define i64 @main.incVal(%"github.com/goplus/llgo/internal/runtime.iface" %0) {
_llgo_0: _llgo_0:
@@ -21,16 +21,6 @@ _llgo_0:
_llgo_1: ; preds = %_llgo_0 _llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1 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 br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0 _llgo_2: ; preds = %_llgo_1, %_llgo_0
@@ -39,17 +29,21 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
define void @main() { define void @main() {
_llgo_0: _llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init() call void @main.init()
%0 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(i64 100) %0 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 2)
%1 = call i64 @main.incVal(%"github.com/goplus/llgo/internal/runtime.iface" %0) %1 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %0, i64 100)
call void (ptr, ...) @printf(ptr @main.format, i64 %1) %2 = call i64 @main.incVal(%"github.com/goplus/llgo/internal/runtime.iface" %1)
%3 = call i32 (ptr, ...) @printf(ptr @0, i64 %2)
ret void ret void
} }
declare void @printf(ptr, ...)
declare i64 @"github.com/goplus/llgo/internal/runtime.I2Int"(%"github.com/goplus/llgo/internal/runtime.iface", 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 ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64)
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr, i64) declare %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr, i64)
declare i32 @printf(ptr, ...)

11
cl/_testrt/builtin/in.go Normal file
View File

@@ -0,0 +1,11 @@
package main
var a int64 = 1<<63 - 1
var b int64 = -1 << 63
var c uint64 = 1<<64 - 1
func main() {
var a = []int{1, 2, 3, 4}
_ = len(a)
_ = len([]int{1, 2, 3, 4})
}

62
cl/_testrt/builtin/out.ll Normal file
View File

@@ -0,0 +1,62 @@
; ModuleID = 'main'
source_filename = "main"
%"github.com/goplus/llgo/internal/runtime.Slice" = type { ptr, i64, i64 }
@main.a = global ptr null
@main.b = global ptr null
@main.c = 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 i64 9223372036854775807, ptr @main.a, align 4
store i64 -9223372036854775808, ptr @main.b, align 4
store i64 -1, ptr @main.c, align 4
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
define void @main() {
_llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init()
%0 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 32)
%1 = getelementptr inbounds i64, ptr %0, i64 0
store i64 1, ptr %1, align 4
%2 = getelementptr inbounds i64, ptr %0, i64 1
store i64 2, ptr %2, align 4
%3 = getelementptr inbounds i64, ptr %0, i64 2
store i64 3, ptr %3, align 4
%4 = getelementptr inbounds i64, ptr %0, i64 3
store i64 4, ptr %4, align 4
%5 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice"(ptr %0, i64 4, i64 4)
%6 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %5)
%7 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 32)
%8 = getelementptr inbounds i64, ptr %7, i64 0
store i64 1, ptr %8, align 4
%9 = getelementptr inbounds i64, ptr %7, i64 1
store i64 2, ptr %9, align 4
%10 = getelementptr inbounds i64, ptr %7, i64 2
store i64 3, ptr %10, align 4
%11 = getelementptr inbounds i64, ptr %7, i64 3
store i64 4, ptr %11, align 4
%12 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice"(ptr %7, i64 4, i64 4)
%13 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %12)
ret void
}
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64)
declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice"(ptr, i64, i64)
declare i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice")

13
cl/_testrt/cstr/in.go Normal file
View File

@@ -0,0 +1,13 @@
package main
import _ "unsafe"
//go:linkname cstr llgo.cstr
func cstr(string) *int8
//go:linkname printf C.printf
func printf(format *int8, __llgo_va_list ...any)
func main() {
printf(cstr("Hello, world\n"))
}

30
cl/_testrt/cstr/out.ll Normal file
View File

@@ -0,0 +1,30 @@
; ModuleID = 'main'
source_filename = "main"
@"main.init$guard" = global ptr null
@0 = private unnamed_addr constant [14 x i8] c"Hello, world\0A\00", align 1
define void @main.init() {
_llgo_0:
%0 = load i1, ptr @"main.init$guard", align 1
br i1 %0, label %_llgo_2, label %_llgo_1
_llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
define void @main() {
_llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init()
call void (ptr, ...) @printf(ptr @0)
ret void
}
declare void @printf(ptr, ...)
declare void @"github.com/goplus/llgo/internal/runtime.init"()

32
cl/_testrt/gblarray/in.go Normal file
View File

@@ -0,0 +1,32 @@
package main
import (
"github.com/goplus/llgo/internal/abi"
"github.com/goplus/llgo/internal/runtime/c"
)
func Basic(kind abi.Kind) *abi.Type {
return basicTypes[kind]
}
var (
basicTypes = [...]*abi.Type{
abi.String: basicType(abi.String),
}
sizeBasicTypes = [...]uintptr{
abi.String: 16,
}
)
func basicType(kind abi.Kind) *abi.Type {
return &abi.Type{
Size_: sizeBasicTypes[kind],
Hash: uint32(kind),
Kind_: uint8(kind),
}
}
func main() {
t := Basic(abi.String)
c.Printf(c.Str("Kind: %d, Size: %d\n"), int(t.Kind_), t.Size_)
}

View File

@@ -0,0 +1,71 @@
; ModuleID = 'main'
source_filename = "main"
%"github.com/goplus/llgo/internal/abi.Type" = type { i64, i64, i32, i8, i8, i8, i8, ptr, ptr, i32, i32 }
@main.basicTypes = global ptr null
@"main.init$guard" = global ptr null
@main.sizeBasicTypes = global ptr null
@0 = private unnamed_addr constant [20 x i8] c"Kind: %d, Size: %d\0A\00", align 1
define ptr @main.Basic(i64 %0) {
_llgo_0:
%1 = getelementptr inbounds ptr, ptr @main.basicTypes, i64 %0
%2 = load ptr, ptr %1, align 8
ret ptr %2
}
define ptr @main.basicType(i64 %0) {
_llgo_0:
%1 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 48)
%2 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.Type", ptr %1, i32 0, i32 0
%3 = getelementptr inbounds i64, ptr @main.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 2
%6 = trunc i64 %0 to i32
%7 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.Type", ptr %1, i32 0, i32 6
%8 = trunc i64 %0 to i8
store i64 %4, ptr %2, align 4
store i32 %6, ptr %5, align 4
store i8 %8, ptr %7, align 1
ret ptr %1
}
define void @main.init() {
_llgo_0:
%0 = load i1, ptr @"main.init$guard", align 1
br i1 %0, label %_llgo_2, label %_llgo_1
_llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1
call void @"github.com/goplus/llgo/internal/abi.init"()
store i64 16, ptr getelementptr inbounds (i64, ptr @main.sizeBasicTypes, i64 24), align 4
%1 = call ptr @main.basicType(i64 24)
store ptr %1, ptr getelementptr inbounds (ptr, ptr @main.basicTypes, i64 24), align 8
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
define void @main() {
_llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init()
%0 = call ptr @main.Basic(i64 24)
%1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.Type", ptr %0, i32 0, i32 6
%2 = load i8, ptr %1, align 1
%3 = sext i8 %2 to i64
%4 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.Type", ptr %0, i32 0, i32 0
%5 = load i64, ptr %4, align 4
%6 = call i32 (ptr, ...) @printf(ptr @0, i64 %3, i64 %5)
ret void
}
declare ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64)
declare void @"github.com/goplus/llgo/internal/abi.init"()
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare i32 @printf(ptr, ...)

View File

@@ -29,12 +29,15 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
define void @main() { define void @main() {
_llgo_0: _llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init() call void @main.init()
%0 = call i32 @strlen(ptr @main.format) %0 = call i32 @strlen(ptr @main.format)
call void (ptr, ...) @printf(ptr @main.format, i32 %0) call void (ptr, ...) @printf(ptr @main.format, i32 %0)
ret void ret void
} }
declare void @printf(ptr, ...) declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare i32 @strlen(ptr) declare i32 @strlen(ptr)
declare void @printf(ptr, ...)

13
cl/_testrt/map/in.go Normal file
View File

@@ -0,0 +1,13 @@
package main
/*
import (
"github.com/goplus/llgo/internal/runtime/c"
)
*/
func main() {
a := map[int]int{23: 100, 7: 29}
_ = a
// c.Printf(c.Str("Hello %d\n"), a[23])
}

29
cl/_testrt/map/out.ll Normal file
View File

@@ -0,0 +1,29 @@
; ModuleID = 'main'
source_filename = "main"
@"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
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
define void @main() {
_llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init()
%0 = call ptr @"github.com/goplus/llgo/internal/runtime.MakeSmallMap"()
ret void
}
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare ptr @"github.com/goplus/llgo/internal/runtime.MakeSmallMap"()

5
cl/_testrt/panic/in.go Normal file
View File

@@ -0,0 +1,5 @@
package main
func main() {
panic("panic message")
}

39
cl/_testrt/panic/out.ll Normal file
View File

@@ -0,0 +1,39 @@
; ModuleID = 'main'
source_filename = "main"
%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 }
%"github.com/goplus/llgo/internal/runtime.iface" = type { ptr, ptr }
@"main.init$guard" = global ptr null
@0 = private unnamed_addr constant [14 x i8] c"panic message\00", align 1
define void @main.init() {
_llgo_0:
%0 = load i1, ptr @"main.init$guard", align 1
br i1 %0, label %_llgo_2, label %_llgo_1
_llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
define void @main() {
_llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init()
%0 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @0, i64 13)
%1 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyString"(%"github.com/goplus/llgo/internal/runtime.String" %0)
call void @"github.com/goplus/llgo/internal/runtime.TracePanic"(%"github.com/goplus/llgo/internal/runtime.iface" %1)
unreachable
}
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr, i64)
declare %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyString"(%"github.com/goplus/llgo/internal/runtime.String")
declare void @"github.com/goplus/llgo/internal/runtime.TracePanic"(%"github.com/goplus/llgo/internal/runtime.iface")

View File

@@ -11,7 +11,6 @@ _llgo_0:
_llgo_1: ; preds = %_llgo_0 _llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1 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 72, ptr @main.format, align 1
store i8 101, ptr getelementptr inbounds (i8, ptr @main.format, i64 1), 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 2), align 1
@@ -30,14 +29,15 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
define void @main() { define void @main() {
_llgo_0: _llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init() call void @main.init()
%0 = call i32 @strlen(ptr @main.format) %0 = call i32 @strlen(ptr @main.format)
call void (ptr, ...) @"github.com/goplus/llgo/cl/internal/libc.Printf"(ptr @main.format, i32 %0) call void (ptr, ...) @printf(ptr @main.format, i32 %0)
ret void ret void
} }
declare void @"github.com/goplus/llgo/cl/internal/libc.init"() declare void @printf(ptr, ...)
declare i32 @strlen(ptr) declare i32 @strlen(ptr)
declare void @"github.com/goplus/llgo/cl/internal/libc.Printf"(ptr, ...) declare void @"github.com/goplus/llgo/internal/runtime.init"()

View File

@@ -56,6 +56,7 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
define void @main() { define void @main() {
_llgo_0: _llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init() call void @main.init()
%0 = alloca %main.Foo, align 8 %0 = alloca %main.Foo, align 8
%1 = getelementptr inbounds %main.Foo, ptr %0, i32 0, i32 0 %1 = getelementptr inbounds %main.Foo, ptr %0, i32 0, i32 0
@@ -68,3 +69,5 @@ _llgo_0:
} }
declare void @printf(ptr, ...) declare void @printf(ptr, ...)
declare void @"github.com/goplus/llgo/internal/runtime.init"()

16
cl/_testrt/sum/in.go Normal file
View File

@@ -0,0 +1,16 @@
package main
import (
"github.com/goplus/llgo/internal/runtime/c"
)
func sum(args ...int) (ret int) {
for _, v := range args {
ret += v
}
return
}
func main() {
c.Printf(c.Str("Hello %d\n"), sum(1, 2, 3, 4))
}

74
cl/_testrt/sum/out.ll Normal file
View File

@@ -0,0 +1,74 @@
; ModuleID = 'main'
source_filename = "main"
%"github.com/goplus/llgo/internal/runtime.Slice" = type { ptr, i64, i64 }
@"main.init$guard" = global ptr null
@0 = private unnamed_addr constant [10 x i8] c"Hello %d\0A\00", align 1
define void @main.init() {
_llgo_0:
%0 = load i1, ptr @"main.init$guard", align 1
br i1 %0, label %_llgo_2, label %_llgo_1
_llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
define void @main() {
_llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init()
%0 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 32)
%1 = getelementptr inbounds i64, ptr %0, i64 0
store i64 1, ptr %1, align 4
%2 = getelementptr inbounds i64, ptr %0, i64 1
store i64 2, ptr %2, align 4
%3 = getelementptr inbounds i64, ptr %0, i64 2
store i64 3, ptr %3, align 4
%4 = getelementptr inbounds i64, ptr %0, i64 3
store i64 4, ptr %4, align 4
%5 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice"(ptr %0, i64 4, i64 4)
%6 = call i64 @main.sum(%"github.com/goplus/llgo/internal/runtime.Slice" %5)
%7 = call i32 (ptr, ...) @printf(ptr @0, i64 %6)
ret void
}
define i64 @main.sum(%"github.com/goplus/llgo/internal/runtime.Slice" %0) {
_llgo_0:
%1 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %0)
br label %_llgo_1
_llgo_1: ; preds = %_llgo_2, %_llgo_0
%2 = phi i64 [ 0, %_llgo_0 ], [ %9, %_llgo_2 ]
%3 = phi i64 [ -1, %_llgo_0 ], [ %4, %_llgo_2 ]
%4 = add i64 %3, 1
%5 = icmp slt i64 %4, %1
br i1 %5, label %_llgo_2, label %_llgo_3
_llgo_2: ; preds = %_llgo_1
%6 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %0)
%7 = getelementptr inbounds i64, ptr %6, i64 %4
%8 = load i64, ptr %7, align 4
%9 = add i64 %2, %8
br label %_llgo_1
_llgo_3: ; preds = %_llgo_1
ret i64 %2
}
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64)
declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice"(ptr, i64, i64)
declare i32 @printf(ptr, ...)
declare i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice")
declare ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice")

View File

@@ -45,8 +45,9 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
define void @main() { define void @main() {
_llgo_0: _llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init() call void @main.init()
%0 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16) %0 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 5)
%1 = getelementptr inbounds { i32, i1 }, ptr %0, i32 0, i32 0 %1 = getelementptr inbounds { i32, i1 }, ptr %0, i32 0, i32 0
%2 = getelementptr inbounds { i32, i1 }, ptr %0, i32 0, i32 1 %2 = getelementptr inbounds { i32, i1 }, ptr %0, i32 0, i32 1
store i32 100, ptr %1, align 4 store i32 100, ptr %1, align 4
@@ -57,4 +58,6 @@ _llgo_0:
declare void @printf(ptr, ...) declare void @printf(ptr, ...)
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64) declare ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64)

View File

@@ -0,0 +1,14 @@
package main
import (
"github.com/goplus/llgo/internal/runtime/c"
)
func foo() {
c.Unreachable()
}
func main() {
foo()
c.Printf(c.Str("Hello\n"))
}

View File

@@ -0,0 +1,37 @@
; ModuleID = 'main'
source_filename = "main"
@"main.init$guard" = global ptr null
@0 = private unnamed_addr constant [7 x i8] c"Hello\0A\00", align 1
define void @main.foo() {
_llgo_0:
unreachable
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
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
define void @main() {
_llgo_0:
call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init()
call void @main.foo()
%0 = call i32 (ptr, ...) @printf(ptr @0)
ret void
}
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare i32 @printf(ptr, ...)

View File

@@ -17,6 +17,7 @@
package cl package cl
import ( import (
"go/constant"
"go/types" "go/types"
"testing" "testing"
@@ -24,6 +25,69 @@ import (
"golang.org/x/tools/go/ssa" "golang.org/x/tools/go/ssa"
) )
func TestErrAlloca(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Fatal("alloca: no error?")
}
}()
var ctz context
ctz.alloca(nil, nil)
}
func TestCStrNoArgs(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Fatal("cstr: no error?")
}
}()
cstr(nil, nil)
}
func TestCStrNonconst(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Fatal("cstr: no error?")
}
}()
cstr(nil, []ssa.Value{&ssa.Parameter{}})
}
func TestPkgNoInit(t *testing.T) {
pkg := types.NewPackage("foo", "foo")
ctx := &context{
goTyps: pkg,
loaded: make(map[*types.Package]*pkgInfo),
}
if ctx.pkgNoInit(pkg) {
t.Fatal("pkgNoInit?")
}
}
func TestPkgKind(t *testing.T) {
if v := pkgKind("noinit"); v != PkgNoInit {
t.Fatal("pkgKind:", v)
}
if v := pkgKind(""); v != PkgLLGo {
t.Fatal("pkgKind:", v)
}
}
func TestPkgKindOf(t *testing.T) {
if v := PkgKindOf(types.Unsafe); v != PkgDeclOnly {
t.Fatal("PkgKindOf unsafe:", v)
}
pkg := types.NewPackage("foo", "foo")
pkg.Scope().Insert(
types.NewConst(
0, pkg, "LLGoPackage", types.Typ[types.String],
constant.MakeString("noinit")),
)
if v := PkgKindOf(pkg); v != PkgNoInit {
t.Fatal("PkgKindOf foo:", v)
}
}
func TestIsAny(t *testing.T) { func TestIsAny(t *testing.T) {
if isAny(types.Typ[types.UntypedInt]) { if isAny(types.Typ[types.UntypedInt]) {
t.Fatal("isAny?") t.Fatal("isAny?")
@@ -48,7 +112,7 @@ func TestIgnoreName(t *testing.T) {
func TestErrImport(t *testing.T) { func TestErrImport(t *testing.T) {
var ctx context var ctx context
pkg := types.NewPackage("foo", "foo") pkg := types.NewPackage("foo", "foo")
ctx.importPkg(pkg) ctx.importPkg(pkg, nil)
} }
func TestErrInitLinkname(t *testing.T) { func TestErrInitLinkname(t *testing.T) {

View File

@@ -113,6 +113,14 @@ func TestCompileEx(t *testing.T, src any, fname, expected string) {
} }
foo.WriteTo(os.Stderr) foo.WriteTo(os.Stderr)
prog := llssa.NewProgram(nil) prog := llssa.NewProgram(nil)
prog.SetRuntime(func() *types.Package {
rt, err := imp.Import(llssa.PkgRuntime)
if err != nil {
t.Fatal("load runtime failed:", err)
}
return rt
})
ret, err := cl.NewPackage(prog, foo, files) ret, err := cl.NewPackage(prog, foo, files)
if err != nil { if err != nil {
t.Fatal("cl.NewPackage failed:", err) t.Fatal("cl.NewPackage failed:", err)

View File

@@ -61,12 +61,12 @@ const (
fnIgnore fnIgnore
) )
func funcKind(vfn ssa.Value) int { func (p *context) funcKind(vfn ssa.Value) int {
if fn, ok := vfn.(*ssa.Function); ok && fn.Signature.Recv() == nil { if fn, ok := vfn.(*ssa.Function); ok && fn.Signature.Recv() == nil {
params := fn.Signature.Params() params := fn.Signature.Params()
n := params.Len() n := params.Len()
if n == 0 { if n == 0 {
if fn.Name() == "init" && ignorePkgInit(fn.Pkg.Pkg.Path()) { if fn.Name() == "init" && p.pkgNoInit(fn.Pkg.Pkg) {
return fnIgnore return fnIgnore
} }
} else { } else {
@@ -79,10 +79,10 @@ func funcKind(vfn ssa.Value) int {
return fnNormal return fnNormal
} }
func ignorePkgInit(pkgPath string) bool { func (p *context) pkgNoInit(pkg *types.Package) bool {
switch pkgPath { p.ensureLoaded(pkg)
case "unsafe", "syscall", "runtime/cgo": if i, ok := p.loaded[pkg]; ok {
return true return i.kind >= PkgNoInit
} }
return false return false
} }
@@ -113,13 +113,22 @@ func inPkg(name, pkg string) bool {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
type none = struct{}
type instrOrValue interface { type instrOrValue interface {
ssa.Instruction ssa.Instruction
ssa.Value ssa.Value
} }
const (
PkgNormal = iota
PkgLLGo
PkgNoInit // noinit: a package that don't need to be initialized
PkgDeclOnly // decl: a package that only have declarations
)
type pkgInfo struct {
kind int
}
type context struct { type context struct {
prog llssa.Program prog llssa.Program
pkg llssa.Package pkg llssa.Package
@@ -129,10 +138,11 @@ type context struct {
goTyps *types.Package goTyps *types.Package
goPkg *ssa.Package goPkg *ssa.Package
link map[string]string // pkgPath.nameInPkg => linkname link map[string]string // pkgPath.nameInPkg => linkname
loaded map[*types.Package]none // loaded packages loaded map[*types.Package]*pkgInfo // loaded packages
bvals map[ssa.Value]llssa.Expr // block values bvals map[ssa.Value]llssa.Expr // block values
vargs map[*ssa.Alloc][]llssa.Expr // varargs vargs map[*ssa.Alloc][]llssa.Expr // varargs
inits []func() inits []func()
phis []func()
} }
func (p *context) compileType(pkg llssa.Package, t *ssa.Type) { func (p *context) compileType(pkg llssa.Package, t *ssa.Type) {
@@ -180,8 +190,9 @@ func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) {
func (p *context) compileFunc(pkg llssa.Package, pkgTypes *types.Package, f *ssa.Function) { func (p *context) compileFunc(pkg llssa.Package, pkgTypes *types.Package, f *ssa.Function) {
sig := f.Signature sig := f.Signature
name, ok := p.funcName(pkgTypes, f, true) name, ftype := p.funcName(pkgTypes, f, true)
if !ok { // ignored switch ftype {
case ignoredFunc, llgoInstr: // llgo extended instructions
return return
} }
if debugInstr { if debugInstr {
@@ -193,6 +204,7 @@ func (p *context) compileFunc(pkg llssa.Package, pkgTypes *types.Package, f *ssa
defer func() { defer func() {
p.fn = nil p.fn = nil
}() }()
p.phis = nil
nblk := len(f.Blocks) nblk := len(f.Blocks)
if nblk == 0 { // external function if nblk == 0 { // external function
return return
@@ -209,6 +221,9 @@ func (p *context) compileFunc(pkg llssa.Package, pkgTypes *types.Package, f *ssa
for i, block := range f.Blocks { for i, block := range f.Blocks {
p.compileBlock(b, block, i == 0 && name == "main") p.compileBlock(b, block, i == 0 && name == "main")
} }
for _, phi := range p.phis {
phi()
}
}) })
} }
@@ -216,8 +231,9 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, doInit bo
ret := p.fn.Block(block.Index) ret := p.fn.Block(block.Index)
b.SetBlock(ret) b.SetBlock(ret)
if doInit { if doInit {
fn := p.pkg.FuncOf("main.init") pkg := p.pkg
b.Call(fn.Expr) callRuntimeInit(b, pkg)
b.Call(pkg.FuncOf("main.init").Expr)
} }
for _, instr := range block.Instrs { for _, instr := range block.Instrs {
p.compileInstr(b, instr) p.compileInstr(b, instr)
@@ -225,6 +241,15 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, doInit bo
return ret return ret
} }
const (
RuntimeInit = llssa.PkgRuntime + ".init"
)
func callRuntimeInit(b llssa.Builder, pkg llssa.Package) {
fn := pkg.NewFunc(RuntimeInit, types.NewSignatureType(nil, nil, nil, nil, nil, false))
b.Call(fn.Expr)
}
func isAny(t types.Type) bool { func isAny(t types.Type) bool {
if t, ok := t.(*types.Interface); ok { if t, ok := t.(*types.Interface); ok {
return t.Empty() return t.Empty()
@@ -260,6 +285,37 @@ func (p *context) checkVArgs(v *ssa.Alloc, t *types.Pointer) bool {
return false return false
} }
// func cstr(string) *int8
func cstr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
if len(args) == 1 {
if c, ok := args[0].(*ssa.Const); ok {
if v := c.Value; v.Kind() == constant.String {
sv := constant.StringVal(v)
return b.CStr(sv)
}
}
}
panic("cstr(<string-literal>): invalid arguments")
}
// func alloca(size uintptr) unsafe.Pointer
func (p *context) alloca(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
if len(args) == 1 {
n := p.compileValue(b, args[0])
return b.Alloca(n)
}
panic("alloca(size uintptr): invalid arguments")
}
// func allocaCStr(s string) *int8
func (p *context) allocaCStr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
if len(args) == 1 {
s := p.compileValue(b, args[0])
return b.AllocaCStr(s)
}
panic("allocaCStr(s string): invalid arguments")
}
func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue bool) (ret llssa.Expr) { func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue bool) (ret llssa.Expr) {
if asValue { if asValue {
if v, ok := p.bvals[iv]; ok { if v, ok := p.bvals[iv]; ok {
@@ -271,15 +327,16 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
case *ssa.Call: case *ssa.Call:
call := v.Call call := v.Call
cv := call.Value cv := call.Value
kind := funcKind(cv) kind := p.funcKind(cv)
if kind == fnIgnore { if kind == fnIgnore {
return return
} }
if debugGoSSA { if debugGoSSA {
log.Println(">>> Call", cv, call.Args) log.Println(">>> Call", cv, call.Args)
} }
if builtin, ok := cv.(*ssa.Builtin); ok { switch cv := cv.(type) {
fn := builtin.Name() case *ssa.Builtin:
fn := cv.Name()
if fn == "ssa:wrapnilchk" { // TODO(xsw): check nil ptr if fn == "ssa:wrapnilchk" { // TODO(xsw): check nil ptr
arg := call.Args[0] arg := call.Args[0]
ret = p.compileValue(b, arg) ret = p.compileValue(b, arg)
@@ -288,10 +345,30 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
args := p.compileValues(b, call.Args, kind) args := p.compileValues(b, call.Args, kind)
ret = b.BuiltinCall(fn, args...) ret = b.BuiltinCall(fn, args...)
} }
} else { case *ssa.Function:
fn, ftype := p.funcOf(cv)
switch ftype {
case goFunc, cFunc:
args := p.compileValues(b, call.Args, kind)
ret = b.Call(fn.Expr, args...)
case llgoCstr:
ret = cstr(b, call.Args)
case llgoAlloca:
ret = p.alloca(b, call.Args)
case llgoAllocaCStr:
ret = p.allocaCStr(b, call.Args)
case llgoUnreachable: // func unreachable()
b.Unreachable()
default:
panic("todo")
}
default:
panic("todo")
/*
fn := p.compileValue(b, cv) 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)
@@ -300,6 +377,18 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
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.Phi:
phi := b.Phi(p.prog.Type(v.Type()))
ret = phi.Expr
p.phis = append(p.phis, func() {
vals := p.compileValues(b, v.Edges, 0)
preds := v.Block().Preds
bblks := make([]llssa.BasicBlock, len(preds))
for i, pred := range preds {
bblks[i] = p.fn.Block(pred.Index)
}
phi.AddIncoming(vals, bblks)
})
case *ssa.ChangeType: case *ssa.ChangeType:
t := v.Type() t := v.Type()
x := p.compileValue(b, v.X) x := p.compileValue(b, v.X)
@@ -311,6 +400,12 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
case *ssa.FieldAddr: case *ssa.FieldAddr:
x := p.compileValue(b, v.X) x := p.compileValue(b, v.X)
ret = b.FieldAddr(x, v.Field) ret = b.FieldAddr(x, v.Field)
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.IndexAddr: case *ssa.IndexAddr:
vx := v.X vx := v.X
if _, ok := p.isVArgs(vx); ok { // varargs: this is a varargs index if _, ok := p.isVArgs(vx); ok { // varargs: this is a varargs index
@@ -324,13 +419,25 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
if _, ok := p.isVArgs(vx); ok { // varargs: this is a varargs slice if _, ok := p.isVArgs(vx); ok { // varargs: this is a varargs slice
return return
} }
panic("todo") var low, high, max llssa.Expr
case *ssa.Alloc: x := p.compileValue(b, vx)
t := v.Type().(*types.Pointer) if v.Low != nil {
if p.checkVArgs(v, t) { // varargs: this is a varargs allocation low = p.compileValue(b, v.Low)
return
} }
ret = b.Alloc(t, v.Heap) if v.High != nil {
high = p.compileValue(b, v.High)
}
if v.Max != nil {
max = p.compileValue(b, v.Max)
}
ret = b.Slice(x, low, high, max)
case *ssa.MakeMap:
var nReserve llssa.Expr
t := v.Type()
if v.Reserve != nil {
nReserve = p.compileValue(b, v.Reserve)
}
ret = b.MakeMap(p.prog.Type(t), nReserve)
case *ssa.MakeInterface: case *ssa.MakeInterface:
const ( const (
delayExpr = true // varargs: don't need to convert an expr to any delayExpr = true // varargs: don't need to convert an expr to any
@@ -391,6 +498,11 @@ 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.MapUpdate:
m := p.compileValue(b, v.Map)
key := p.compileValue(b, v.Key)
val := p.compileValue(b, v.Value)
b.MapUpdate(m, key, val)
case *ssa.Panic: case *ssa.Panic:
arg := p.compileValue(b, v.X).Do() arg := p.compileValue(b, v.X).Do()
b.Panic(arg) b.Panic(arg)
@@ -412,13 +524,19 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr {
} }
} }
case *ssa.Function: case *ssa.Function:
fn := p.funcOf(v) panic("unreachable")
/*
fn, ftype := p.funcOf(v)
if ftype >= llgoInstrBase {
panic("can't use llgo instruction as a value")
}
return fn.Expr return fn.Expr
*/
case *ssa.Global: case *ssa.Global:
g := p.varOf(v) g := p.varOf(v)
return g.Expr return g.Expr
case *ssa.Const: case *ssa.Const:
t := v.Type() t := types.Default(v.Type())
return b.Const(v.Value, p.prog.Type(t)) return b.Const(v.Value, p.prog.Type(t))
} }
panic(fmt.Sprintf("compileValue: unknown value - %T\n", v)) panic(fmt.Sprintf("compileValue: unknown value - %T\n", v))
@@ -484,8 +602,10 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll
goTyps: pkgTypes, goTyps: pkgTypes,
goPkg: pkg, goPkg: pkg,
link: make(map[string]string), link: make(map[string]string),
loaded: make(map[*types.Package]none),
vargs: make(map[*ssa.Alloc][]llssa.Expr), vargs: make(map[*ssa.Alloc][]llssa.Expr),
loaded: map[*types.Package]*pkgInfo{
types.Unsafe: {kind: PkgDeclOnly}, // TODO(xsw): PkgNoInit or PkgDeclOnly?
},
} }
ctx.initFiles(pkgPath, files) ctx.initFiles(pkgPath, files)
for _, m := range members { for _, m := range members {

View File

@@ -28,8 +28,8 @@ func testCompile(t *testing.T, src, expected string) {
cltest.TestCompileEx(t, src, "foo.go", expected) cltest.TestCompileEx(t, src, "foo.go", expected)
} }
func TestFromTestcgo(t *testing.T) { func TestFromTestrt(t *testing.T) {
cltest.FromDir(t, "", "./_testcgo", true) cltest.FromDir(t, "", "./_testrt", true)
} }
func TestFromTestdata(t *testing.T) { func TestFromTestdata(t *testing.T) {

View File

@@ -19,6 +19,7 @@ package cl
import ( import (
"bytes" "bytes"
"go/ast" "go/ast"
"go/constant"
"go/token" "go/token"
"go/types" "go/types"
"os" "os"
@@ -43,11 +44,45 @@ func contentOf(m contentMap, file string) (lines contentLines, err error) {
return return
} }
func (p *context) importPkg(pkg *types.Package) { // PkgKindOf returns the kind of a package.
func PkgKindOf(pkg *types.Package) int {
scope := pkg.Scope() scope := pkg.Scope()
if scope.Lookup("LLGoPackage") == nil { kind := pkgKindByScope(scope)
if kind == PkgNormal {
kind = pkgKindByPath(pkg.Path())
}
return kind
}
// decl: a package that only contains declarations
// noinit: a package that does not need to be initialized
func pkgKind(v string) int {
switch v {
case "decl":
return PkgDeclOnly
case "noinit":
return PkgNoInit
}
return PkgLLGo
}
func pkgKindByScope(scope *types.Scope) int {
if v, ok := scope.Lookup("LLGoPackage").(*types.Const); ok {
if v := v.Val(); v.Kind() == constant.String {
return pkgKind(constant.StringVal(v))
}
return PkgLLGo
}
return PkgNormal
}
func (p *context) importPkg(pkg *types.Package, i *pkgInfo) {
scope := pkg.Scope()
kind := pkgKindByScope(scope)
if kind == PkgNormal {
return return
} }
i.kind = kind
fset := p.fset fset := p.fset
names := scope.Names() names := scope.Names()
contents := make(contentMap) contents := make(contentMap)
@@ -99,9 +134,9 @@ func (p *context) initLinkname(pkgPath, line string) {
text := strings.TrimSpace(line[len(linkname):]) text := strings.TrimSpace(line[len(linkname):])
if idx := strings.IndexByte(text, ' '); idx > 0 { if idx := strings.IndexByte(text, ' '); idx > 0 {
link := strings.TrimLeft(text[idx+1:], " ") link := strings.TrimLeft(text[idx+1:], " ")
if strings.Contains(link, ".") { // eg. C.printf, C.strlen if strings.Contains(link, ".") { // eg. C.printf, C.strlen, llgo.cstr
name := pkgPath + "." + text[:idx] name := pkgPath + "." + text[:idx]
p.link[name] = link[2:] p.link[name] = link
} else { } else {
panic(line + ": no specified call convention. eg. //go:linkname Printf C.printf") panic(line + ": no specified call convention. eg. //go:linkname Printf C.printf")
} }
@@ -136,25 +171,59 @@ func checkCgo(fnName string) bool {
(fnName[4] == '_' || strings.HasPrefix(fnName[4:], "Check")) (fnName[4] == '_' || strings.HasPrefix(fnName[4:], "Check"))
} }
func (p *context) funcName(pkg *types.Package, fn *ssa.Function, ignore bool) (string, bool) { const (
ignoredFunc = iota
goFunc
cFunc
llgoInstr = -1
llgoInstrBase = 0x80
llgoUnreachable = llgoInstrBase + 0
llgoCstr = llgoInstrBase + 1
llgoAlloca = llgoInstrBase + 2
llgoAllocaCStr = llgoInstrBase + 3
)
func (p *context) funcName(pkg *types.Package, fn *ssa.Function, ignore bool) (string, int) {
name := funcName(pkg, fn) name := funcName(pkg, fn)
if ignore && ignoreName(name) || checkCgo(fn.Name()) { if ignore && ignoreName(name) || checkCgo(fn.Name()) {
return name, false return name, ignoredFunc
} }
if v, ok := p.link[name]; ok { if v, ok := p.link[name]; ok {
return v, true if strings.HasPrefix(v, "C.") {
return v[2:], cFunc
} }
return name, true if strings.HasPrefix(v, "llgo.") {
return v[5:], llgoInstr
}
return v, goFunc
}
return name, goFunc
} }
func (p *context) funcOf(fn *ssa.Function) llssa.Function { // funcOf returns a function by name and set ftype = goFunc, cFunc, etc.
// or returns nil and set ftype = llgoCstr, llgoAlloca, llgoUnreachable, etc.
func (p *context) funcOf(fn *ssa.Function) (ret llssa.Function, ftype int) {
pkgTypes := p.ensureLoaded(fn.Pkg.Pkg) pkgTypes := p.ensureLoaded(fn.Pkg.Pkg)
pkg := p.pkg pkg := p.pkg
name, _ := p.funcName(pkgTypes, fn, false) name, ftype := p.funcName(pkgTypes, fn, false)
if ret := pkg.FuncOf(name); ret != nil { if ftype == llgoInstr {
return ret switch name {
case "cstr":
ftype = llgoCstr
case "alloca":
ftype = llgoAlloca
case "allocaCStr":
ftype = llgoAllocaCStr
case "unreachable":
ftype = llgoUnreachable
default:
panic("unknown llgo instruction: " + name)
} }
return pkg.NewFunc(name, fn.Signature) } else if ret = pkg.FuncOf(name); ret == nil {
ret = pkg.NewFunc(name, fn.Signature)
}
return
} }
func (p *context) varOf(v *ssa.Global) llssa.Global { func (p *context) varOf(v *ssa.Global) llssa.Global {
@@ -170,9 +239,20 @@ func (p *context) varOf(v *ssa.Global) llssa.Global {
func (p *context) ensureLoaded(pkgTypes *types.Package) *types.Package { func (p *context) ensureLoaded(pkgTypes *types.Package) *types.Package {
if p.goTyps != pkgTypes { if p.goTyps != pkgTypes {
if _, ok := p.loaded[pkgTypes]; !ok { if _, ok := p.loaded[pkgTypes]; !ok {
p.loaded[pkgTypes] = none{} i := &pkgInfo{
p.importPkg(pkgTypes) kind: pkgKindByPath(pkgTypes.Path()),
}
p.loaded[pkgTypes] = i
p.importPkg(pkgTypes, i)
} }
} }
return pkgTypes return pkgTypes
} }
func pkgKindByPath(pkgPath string) int {
switch pkgPath {
case "syscall", "runtime/cgo", "unsafe":
return PkgDeclOnly
}
return PkgNormal
}

View File

@@ -4,7 +4,7 @@ import "C"
import _ "unsafe" import _ "unsafe"
const ( const (
LLGoPackage = true LLGoPackage = "decl"
) )
//go:linkname Printf C.printf //go:linkname Printf C.printf

2
go.mod
View File

@@ -5,7 +5,7 @@ go 1.18
require ( require (
github.com/aykevl/go-wasm v0.0.1 github.com/aykevl/go-wasm v0.0.1
github.com/goplus/gogen v1.15.2 github.com/goplus/gogen v1.15.2
github.com/goplus/llvm v0.7.2 github.com/goplus/llvm v0.7.3
github.com/goplus/mod v0.13.10 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.20.0 golang.org/x/tools v0.20.0

6
go.sum
View File

@@ -2,10 +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/llvm v0.7.1 h1:B12Fr/wc3pAsq5PLuac9u9IuKpLRuCufdVAeGDP/MRw= github.com/goplus/llvm v0.7.3 h1:I7UkAO4kzn0Es2iHKRpGU1LjYQ452XwYfsSs1OAAXk8=
github.com/goplus/llvm v0.7.1/go.mod h1:PeVK8GgzxwAYCiMiUAJb5wJR6xbhj989tu9oulKLLT4= github.com/goplus/llvm v0.7.3/go.mod h1:PeVK8GgzxwAYCiMiUAJb5wJR6xbhj989tu9oulKLLT4=
github.com/goplus/llvm v0.7.2 h1:NL3LlwAmYVCGA6yV40AjOvMDKl2dbCqoYPtugmLQK+E=
github.com/goplus/llvm v0.7.2/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=

14
internal/abi/map.go Normal file
View File

@@ -0,0 +1,14 @@
// Copyright 2023 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 abi
// Map constants common to several packages
// runtime/runtime-gdb.py:MapTypePrinter contains its own copy
const (
MapBucketCountBits = 3 // log2 of number of elements in a bucket.
MapBucketCount = 1 << MapBucketCountBits
MapMaxKeyBytes = 128 // Must fit in a uint8.
MapMaxElemBytes = 128 // Must fit in a uint8.
)

View File

@@ -126,7 +126,7 @@ func Do(args []string, conf *Config) {
return rt[0].Types return rt[0].Types
}) })
buildAllPkgs(prog, initial, mode, verbose) pkgs := buildAllPkgs(prog, initial, mode, verbose)
var runtimeFiles []string var runtimeFiles []string
if rt != nil { if rt != nil {
@@ -136,12 +136,11 @@ func Do(args []string, conf *Config) {
nErr := 0 nErr := 0
for _, pkg := range initial { for _, pkg := range initial {
if pkg.Name == "main" { if pkg.Name == "main" {
nErr += linkMainPkg(pkg, runtimeFiles, conf, mode, verbose) nErr += linkMainPkg(pkg, pkgs, runtimeFiles, conf, mode, verbose)
} }
} }
if nErr > 0 { if nErr > 0 {
fmt.Fprintf(os.Stderr, "%d errors occurred\n", nErr) os.Exit(nErr)
os.Exit(1)
} }
} }
} }
@@ -154,11 +153,14 @@ func isNeedRuntime(pkg *packages.Package) bool {
return pkg.ID == "" return pkg.ID == ""
} }
func buildAllPkgs(prog llssa.Program, initial []*packages.Package, mode Mode, verbose bool) { func buildAllPkgs(prog llssa.Program, initial []*packages.Package, mode Mode, verbose bool) (pkgs []*aPackage) {
// Create SSA-form program representation. // Create SSA-form program representation.
ssaProg, pkgs, errPkgs := allPkgs(initial, ssa.SanityCheckFunctions) ssaProg, pkgs, errPkgs := allPkgs(initial, ssa.SanityCheckFunctions)
ssaProg.Build() ssaProg.Build()
for _, errPkg := range errPkgs { for _, errPkg := range errPkgs {
for _, err := range errPkg.Errors {
fmt.Fprintln(os.Stderr, err)
}
fmt.Fprintln(os.Stderr, "cannot build SSA for package", errPkg) fmt.Fprintln(os.Stderr, "cannot build SSA for package", errPkg)
} }
for _, pkg := range pkgs { for _, pkg := range pkgs {
@@ -167,9 +169,10 @@ func buildAllPkgs(prog llssa.Program, initial []*packages.Package, mode Mode, ve
setNeedRuntime(pkg.Package) setNeedRuntime(pkg.Package)
} }
} }
return
} }
func linkMainPkg(pkg *packages.Package, runtimeFiles []string, conf *Config, mode Mode, verbose bool) (nErr int) { func linkMainPkg(pkg *packages.Package, pkgs []*aPackage, runtimeFiles []string, conf *Config, mode Mode, verbose bool) (nErr int) {
pkgPath := pkg.PkgPath pkgPath := pkg.PkgPath
name := path.Base(pkgPath) name := path.Base(pkgPath)
app := conf.OutFile app := conf.OutFile
@@ -183,7 +186,7 @@ func linkMainPkg(pkg *packages.Package, runtimeFiles []string, conf *Config, mod
args[2] = "-Wno-override-module" args[2] = "-Wno-override-module"
needRuntime := false needRuntime := false
packages.Visit([]*packages.Package{pkg}, nil, func(p *packages.Package) { packages.Visit([]*packages.Package{pkg}, nil, func(p *packages.Package) {
if p.PkgPath != "unsafe" { // TODO(xsw): maybe can remove this special case if p.ExportFile != "" && !isRuntimePkg(p.PkgPath) { // skip packages that only contain declarations
args = append(args, p.ExportFile+".ll") args = append(args, p.ExportFile+".ll")
if !needRuntime { if !needRuntime {
needRuntime = isNeedRuntime(p) needRuntime = isNeedRuntime(p)
@@ -192,6 +195,17 @@ func linkMainPkg(pkg *packages.Package, runtimeFiles []string, conf *Config, mod
}) })
if needRuntime && runtimeFiles != nil { if needRuntime && runtimeFiles != nil {
args = append(args, runtimeFiles...) args = append(args, runtimeFiles...)
} else {
for _, aPkg := range pkgs {
if aPkg.Package == pkg { // make empty runtime.init if no runtime needed
lpkg := aPkg.LPkg
lpkg.FuncOf(cl.RuntimeInit).MakeBody(1).Return()
if needLLFile(mode) {
file := pkg.ExportFile + ".ll"
os.WriteFile(file, []byte(lpkg.String()), 0644)
}
}
}
} }
if verbose || mode != ModeRun { if verbose || mode != ModeRun {
@@ -204,7 +218,9 @@ func linkMainPkg(pkg *packages.Package, runtimeFiles []string, conf *Config, mod
}() }()
// TODO(xsw): show work // TODO(xsw): show work
// fmt.Fprintln(os.Stderr, "clang", args) if verbose {
fmt.Fprintln(os.Stderr, "clang", args)
}
err := clang.New("").Exec(args...) err := clang.New("").Exec(args...)
check(err) check(err)
@@ -218,8 +234,14 @@ func linkMainPkg(pkg *packages.Package, runtimeFiles []string, conf *Config, mod
return return
} }
func buildPkg(prog llssa.Program, aPkg aPackage, mode Mode, verbose bool) { func buildPkg(prog llssa.Program, aPkg *aPackage, mode Mode, verbose bool) {
pkg := aPkg.Package pkg := aPkg.Package
if cl.PkgKindOf(pkg.Types) == cl.PkgDeclOnly {
// skip packages that only contain declarations
// and set no export file
pkg.ExportFile = ""
return
}
pkgPath := pkg.PkgPath pkgPath := pkg.PkgPath
if verbose { if verbose {
fmt.Fprintln(os.Stderr, pkgPath) fmt.Fprintln(os.Stderr, pkgPath)
@@ -233,14 +255,16 @@ func buildPkg(prog llssa.Program, aPkg aPackage, mode Mode, verbose bool) {
file := pkg.ExportFile + ".ll" file := pkg.ExportFile + ".ll"
os.WriteFile(file, []byte(ret.String()), 0644) os.WriteFile(file, []byte(ret.String()), 0644)
} }
aPkg.LPkg = ret
} }
type aPackage struct { type aPackage struct {
*packages.Package *packages.Package
SSA *ssa.Package SSA *ssa.Package
LPkg llssa.Package
} }
func allPkgs(initial []*packages.Package, mode ssa.BuilderMode) (prog *ssa.Program, all []aPackage, errs []*packages.Package) { func allPkgs(initial []*packages.Package, mode ssa.BuilderMode) (prog *ssa.Program, all []*aPackage, errs []*packages.Package) {
var fset *token.FileSet var fset *token.FileSet
if len(initial) > 0 { if len(initial) > 0 {
fset = initial[0].Fset fset = initial[0].Fset
@@ -250,7 +274,7 @@ func allPkgs(initial []*packages.Package, mode ssa.BuilderMode) (prog *ssa.Progr
packages.Visit(initial, nil, func(p *packages.Package) { packages.Visit(initial, nil, func(p *packages.Package) {
if p.Types != nil && !p.IllTyped { if p.Types != nil && !p.IllTyped {
ssaPkg := prog.CreatePackage(p.Types, p.Syntax, p.TypesInfo, true) ssaPkg := prog.CreatePackage(p.Types, p.Syntax, p.TypesInfo, true)
all = append(all, aPackage{p, ssaPkg}) all = append(all, &aPackage{p, ssaPkg, nil})
} else { } else {
errs = append(errs, p) errs = append(errs, p)
} }
@@ -320,14 +344,28 @@ func allLinkFiles(rt []*packages.Package) (outFiles []string) {
outFiles = make([]string, 0, len(rt)) outFiles = make([]string, 0, len(rt))
root := rootLLGo(rt[0]) root := rootLLGo(rt[0])
packages.Visit(rt, nil, func(p *packages.Package) { packages.Visit(rt, nil, func(p *packages.Package) {
if isPkgInLLGo(p.PkgPath) { pkgPath := p.PkgPath
outFile := filepath.Join(root+p.PkgPath[len(llgoModPath):], "llgo_autogen.ll") if isRuntimePkg(pkgPath) {
outFile := filepath.Join(root+pkgPath[len(llgoModPath):], "llgo_autogen.ll")
outFiles = append(outFiles, outFile) outFiles = append(outFiles, outFile)
} }
}) })
return return
} }
const (
pkgAbi = llgoModPath + "/internal/abi"
pkgRuntime = llgoModPath + "/internal/runtime"
)
func isRuntimePkg(pkgPath string) bool {
switch pkgPath {
case pkgRuntime, pkgAbi:
return true
}
return false
}
// TODO(xsw): llgo root dir // TODO(xsw): llgo root dir
func rootLLGo(runtime *packages.Package) string { func rootLLGo(runtime *packages.Package) string {
return runtime.Module.Dir return runtime.Module.Dir
@@ -337,6 +375,7 @@ const (
llgoModPath = "github.com/goplus/llgo" llgoModPath = "github.com/goplus/llgo"
) )
/*
func isPkgInLLGo(pkgPath string) bool { func isPkgInLLGo(pkgPath string) bool {
return isPkgInMod(pkgPath, llgoModPath) return isPkgInMod(pkgPath, llgoModPath)
} }
@@ -348,6 +387,7 @@ func isPkgInMod(pkgPath, modPath string) bool {
} }
return false return false
} }
*/
func check(err error) { func check(err error) {
if err != nil { if err != nil {

View File

@@ -66,7 +66,9 @@ func Gen(pkgPath, inFile string, src any) string {
&types.Config{Importer: imp}, fset, pkg, files, ssa.SanityCheckFunctions) &types.Config{Importer: imp}, fset, pkg, files, ssa.SanityCheckFunctions)
check(err) check(err)
if Verbose {
ssaPkg.WriteTo(os.Stderr) ssaPkg.WriteTo(os.Stderr)
}
prog := llssa.NewProgram(nil) prog := llssa.NewProgram(nil)
ret, err := cl.NewPackage(prog, ssaPkg, files) ret, err := cl.NewPackage(prog, ssaPkg, files)
@@ -80,3 +82,7 @@ func check(err error) {
panic(err) panic(err)
} }
} }
var (
Verbose = true
)

View File

@@ -19,6 +19,8 @@ package llgen
import ( import (
"go/types" "go/types"
"os" "os"
"path/filepath"
"strings"
"github.com/goplus/llgo/cl" "github.com/goplus/llgo/cl"
"golang.org/x/tools/go/packages" "golang.org/x/tools/go/packages"
@@ -37,7 +39,7 @@ const (
func GenFrom(fileOrPkg string) string { func GenFrom(fileOrPkg string) string {
cfg := &packages.Config{ cfg := &packages.Config{
Mode: loadSyntax, Mode: loadSyntax | packages.NeedDeps,
} }
initial, err := packages.Load(cfg, fileOrPkg) initial, err := packages.Load(cfg, fileOrPkg)
check(err) check(err)
@@ -55,6 +57,10 @@ func GenFrom(fileOrPkg string) string {
return rt[0].Types return rt[0].Types
}) })
if Verbose {
ssaPkg.WriteTo(os.Stderr)
}
ret, err := cl.NewPackage(prog, ssaPkg, pkg.Syntax) ret, err := cl.NewPackage(prog, ssaPkg, pkg.Syntax)
check(err) check(err)
@@ -66,3 +72,23 @@ func DoFile(fileOrPkg, outFile string) {
err := os.WriteFile(outFile, []byte(ret), 0644) err := os.WriteFile(outFile, []byte(ret), 0644)
check(err) check(err)
} }
func SmartDoFile(inFile string, pkgPath ...string) {
dir, _ := filepath.Split(inFile)
fname := "llgo_autogen.ll"
if inCompilerDir(dir) {
fname = "out.ll"
}
outFile := dir + fname
if len(pkgPath) > 0 {
Do(pkgPath[0], inFile, outFile)
} else {
DoFile(inFile, outFile)
}
}
func inCompilerDir(dir string) bool {
dir, _ = filepath.Abs(dir)
return strings.Contains(filepath.ToSlash(dir), "/llgo/cl/")
}

54
internal/runtime/c/c.go Normal file
View File

@@ -0,0 +1,54 @@
/*
* 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 c
import "C"
import "unsafe"
const (
LLGoPackage = "decl"
)
type (
Char = int8
Int = C.int
Pointer = unsafe.Pointer
)
//go:linkname Str llgo.cstr
func Str(string) *Char
//go:linkname Alloca llgo.alloca
func Alloca(size uintptr) Pointer
//go:linkname AllocaCStr llgo.allocaCStr
func AllocaCStr(s string) *Char
//go:linkname Unreachable llgo.unreachable
func Unreachable()
//go:linkname Rand C.rand
func Rand() Int
//go:linkname Malloc C.malloc
func Malloc(size uintptr) Pointer
//go:linkname Memcpy C.memcpy
func Memcpy(dst, src Pointer, n uintptr) Pointer
//go:linkname Printf C.printf
func Printf(format *Char, __llgo_va_list ...any) Int

View File

@@ -1,16 +1,19 @@
; ModuleID = 'github.com/goplus/llgo/internal/runtime' ; ModuleID = 'github.com/goplus/llgo/internal/runtime'
source_filename = "github.com/goplus/llgo/internal/runtime" source_filename = "github.com/goplus/llgo/internal/runtime"
%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 }
%"github.com/goplus/llgo/internal/runtime.iface" = type { ptr, ptr } %"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.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/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/abi.Type" = type { i64, i64, i32, i8, i8, i8, i8, ptr, ptr, i32, i32 }
%"github.com/goplus/llgo/internal/runtime.hmap" = type { i64, i8, i8, i16, i32, ptr, ptr, i64, ptr }
@"github.com/goplus/llgo/internal/runtime.TyAny" = global ptr null @"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.basicTypes" = global ptr null
@"github.com/goplus/llgo/internal/runtime.init$guard" = global ptr null @"github.com/goplus/llgo/internal/runtime.init$guard" = global ptr null
@"github.com/goplus/llgo/internal/runtime.sizeBasicTypes" = global ptr null @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes" = global ptr null
@0 = private unnamed_addr constant [21 x i8] c"I2Int: type mismatch\00", align 1
@1 = private unnamed_addr constant [11 x i8] c"panic: %s\0A\00", align 1
define ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 %0) { define ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 %0) {
_llgo_0: _llgo_0:
@@ -25,6 +28,33 @@ _llgo_0:
ret ptr %2 ret ptr %2
} }
define ptr @"github.com/goplus/llgo/internal/runtime.CStrCopy"(ptr %0, %"github.com/goplus/llgo/internal/runtime.String" %1) {
_llgo_0:
%2 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
store %"github.com/goplus/llgo/internal/runtime.String" %1, ptr %2, align 8
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %2, i32 0, i32 1
%4 = load i64, ptr %3, align 4
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %2, i32 0, i32 0
%6 = load ptr, ptr %5, align 8
%7 = call ptr @memcpy(ptr %0, ptr %6, i64 %4)
%8 = getelementptr inbounds i8, ptr %0, i64 %4
store i8 0, ptr %8, align 1
ret ptr %0
}
define ptr @"github.com/goplus/llgo/internal/runtime.CStrDup"(%"github.com/goplus/llgo/internal/runtime.String" %0) {
_llgo_0:
%1 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
store %"github.com/goplus/llgo/internal/runtime.String" %0, ptr %1, align 8
%2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %1, i32 0, i32 1
%3 = load i64, ptr %2, align 4
%4 = add i64 %3, 1
%5 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 %4)
%6 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %1, align 8
%7 = call ptr @"github.com/goplus/llgo/internal/runtime.CStrCopy"(ptr %5, %"github.com/goplus/llgo/internal/runtime.String" %6)
ret ptr %7
}
define { i64, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %1) { define { i64, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %1) {
_llgo_0: _llgo_0:
%2 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8 %2 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8
@@ -77,52 +107,54 @@ _llgo_1: ; preds = %_llgo_0
ret i64 %10 ret i64 %10
_llgo_2: ; preds = %_llgo_0 _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") %11 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @0, i64 20)
%12 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyString"(%"github.com/goplus/llgo/internal/runtime.String" %11)
call void @"github.com/goplus/llgo/internal/runtime.TracePanic"(%"github.com/goplus/llgo/internal/runtime.iface" %12)
unreachable unreachable
} }
define %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAny"(ptr %0, ptr %1) { define %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAny"(ptr %0, ptr %1) {
_llgo_0: _llgo_0:
%2 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8 %2 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 32)
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 0 %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %2, i32 0, i32 0
%4 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16) %4 = load ptr, ptr @"github.com/goplus/llgo/internal/runtime.TyAny", align 8
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 0 %5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %2, i32 0, i32 1
%6 = load ptr, ptr @"github.com/goplus/llgo/internal/runtime.TyAny", align 8 %6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %2, i32 0, i32 2
%7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 1 %7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %2, i32 0, i32 4
%8 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 2 %8 = getelementptr inbounds i64, ptr %7, i64 0
%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 %4, ptr %3, align 8
store ptr %0, ptr %5, align 8
store i32 0, ptr %6, align 4
store i64 0, ptr %8, align 4
%9 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8
%10 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %9, i32 0, i32 0
%11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %9, i32 0, i32 1
store ptr %2, ptr %10, align 8
store ptr %1, ptr %11, align 8 store ptr %1, ptr %11, align 8
%12 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, align 8 %12 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %9, align 8
ret %"github.com/goplus/llgo/internal/runtime.iface" %12 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) { define %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %0, i64 %1) {
_llgo_0: _llgo_0:
%2 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8 %2 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 32)
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 0 %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %2, i32 0, i32 0
%4 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16) %4 = load ptr, ptr @"github.com/goplus/llgo/internal/runtime.TyAny", align 8
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 0 %5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %2, i32 0, i32 1
%6 = load ptr, ptr @"github.com/goplus/llgo/internal/runtime.TyAny", align 8 %6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %2, i32 0, i32 2
%7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 1 %7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %2, i32 0, i32 4
%8 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 2 %8 = getelementptr inbounds i64, ptr %7, i64 0
%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 %4, ptr %3, align 8
store ptr %0, ptr %5, align 8
store i32 0, ptr %6, align 4
store i64 0, ptr %8, align 4
%9 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8
%10 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %9, i32 0, i32 0
%11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %9, i32 0, i32 1
%12 = inttoptr i64 %1 to ptr
store ptr %2, ptr %10, align 8
store ptr %12, ptr %11, align 8 store ptr %12, ptr %11, align 8
%13 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, align 8 %13 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %9, align 8
ret %"github.com/goplus/llgo/internal/runtime.iface" %13 ret %"github.com/goplus/llgo/internal/runtime.iface" %13
} }
@@ -130,49 +162,77 @@ define %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo
_llgo_0: _llgo_0:
%1 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16) %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 store %"github.com/goplus/llgo/internal/runtime.String" %0, ptr %1, align 8
%2 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8 %2 = load ptr, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 24), align 8
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 0 %3 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 32)
%4 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16) %4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %3, i32 0, i32 0
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 0 %5 = load ptr, ptr @"github.com/goplus/llgo/internal/runtime.TyAny", align 8
%6 = load ptr, ptr @"github.com/goplus/llgo/internal/runtime.TyAny", align 8 %6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %3, i32 0, i32 1
%7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 1 %7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %3, i32 0, i32 2
%8 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 24) %8 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %3, i32 0, i32 4
%9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 2 %9 = getelementptr inbounds i64, ptr %8, i64 0
%10 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 4 store ptr %5, ptr %4, align 8
%11 = getelementptr inbounds i64, ptr %10, i64 0 store ptr %2, ptr %6, align 8
store ptr %6, ptr %5, align 8 store i32 0, ptr %7, align 4
store ptr %8, ptr %7, align 8 store i64 0, ptr %9, align 4
store i32 0, ptr %9, align 4 %10 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8
store i64 0, ptr %11, align 4 %11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %10, i32 0, i32 0
%12 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 1 %12 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %10, i32 0, i32 1
store ptr %4, ptr %3, align 8 store ptr %3, ptr %11, align 8
store ptr %1, ptr %12, align 8 store ptr %1, ptr %12, align 8
%13 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, align 8 %13 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %10, align 8
ret %"github.com/goplus/llgo/internal/runtime.iface" %13 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) { define %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeInterface"(ptr %0, ptr %1, ptr %2) {
_llgo_0: _llgo_0:
%3 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8 %3 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 32)
%4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %3, i32 0, i32 0 %4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %3, i32 0, i32 0
%5 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16) %5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %3, i32 0, i32 1
%6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %5, i32 0, i32 0 %6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %3, i32 0, i32 2
%7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %5, i32 0, i32 1 %7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %3, i32 0, i32 4
%8 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %5, i32 0, i32 2 %8 = getelementptr inbounds i64, ptr %7, i64 0
%9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %5, i32 0, i32 4 store ptr %0, ptr %4, align 8
%10 = getelementptr inbounds i64, ptr %9, i64 0 store ptr %1, ptr %5, align 8
store ptr %0, ptr %6, align 8 store i32 0, ptr %6, align 4
store ptr %1, ptr %7, align 8 store i64 0, ptr %8, align 4
store i32 0, ptr %8, align 4 %9 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8
store i64 0, ptr %10, align 4 %10 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %9, i32 0, i32 0
%11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %3, i32 0, i32 1 %11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %9, i32 0, i32 1
store ptr %5, ptr %4, align 8 store ptr %3, ptr %10, align 8
store ptr %2, ptr %11, align 8 store ptr %2, ptr %11, align 8
%12 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %3, align 8 %12 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %9, align 8
ret %"github.com/goplus/llgo/internal/runtime.iface" %12 ret %"github.com/goplus/llgo/internal/runtime.iface" %12
} }
declare ptr @malloc(i64) define ptr @"github.com/goplus/llgo/internal/runtime.MakeSmallMap"() {
_llgo_0:
%0 = call ptr @"github.com/goplus/llgo/internal/runtime.makemap_small"()
ret ptr %0
}
define %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice"(ptr %0, i64 %1, i64 %2) {
_llgo_0:
%3 = alloca %"github.com/goplus/llgo/internal/runtime.Slice", align 8
%4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %3, i32 0, i32 0
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %3, i32 0, i32 1
%6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %3, i32 0, i32 2
store ptr %0, ptr %4, align 8
store i64 %1, ptr %5, align 4
store i64 %2, ptr %6, align 4
%7 = load %"github.com/goplus/llgo/internal/runtime.Slice", ptr %3, align 8
ret %"github.com/goplus/llgo/internal/runtime.Slice" %7
}
define %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr %0, i64 %1) {
_llgo_0:
%2 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %2, i32 0, i32 0
%4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %2, i32 0, i32 1
store ptr %0, ptr %3, align 8
store i64 %1, ptr %4, align 4
%5 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %2, align 8
ret %"github.com/goplus/llgo/internal/runtime.String" %5
}
define %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NilSlice"() { define %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NilSlice"() {
_llgo_0: _llgo_0:
@@ -187,19 +247,90 @@ _llgo_0:
ret %"github.com/goplus/llgo/internal/runtime.Slice" %4 ret %"github.com/goplus/llgo/internal/runtime.Slice" %4
} }
define ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %0) {
_llgo_0:
%1 = alloca %"github.com/goplus/llgo/internal/runtime.Slice", align 8
store %"github.com/goplus/llgo/internal/runtime.Slice" %0, ptr %1, align 8
%2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %1, i32 0, i32 0
%3 = load ptr, ptr %2, align 8
ret ptr %3
}
define i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %0) {
_llgo_0:
%1 = alloca %"github.com/goplus/llgo/internal/runtime.Slice", align 8
store %"github.com/goplus/llgo/internal/runtime.Slice" %0, ptr %1, align 8
%2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %1, i32 0, i32 1
%3 = load i64, ptr %2, align 4
ret i64 %3
}
define ptr @"github.com/goplus/llgo/internal/runtime.StringData"(%"github.com/goplus/llgo/internal/runtime.String" %0) {
_llgo_0:
%1 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
store %"github.com/goplus/llgo/internal/runtime.String" %0, ptr %1, align 8
%2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %1, i32 0, i32 0
%3 = load ptr, ptr %2, align 8
ret ptr %3
}
define i64 @"github.com/goplus/llgo/internal/runtime.StringLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %0) {
_llgo_0:
%1 = alloca %"github.com/goplus/llgo/internal/runtime.Slice", align 8
store %"github.com/goplus/llgo/internal/runtime.Slice" %0, ptr %1, align 8
%2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %1, i32 0, i32 1
%3 = load i64, ptr %2, align 4
ret i64 %3
}
define void @"github.com/goplus/llgo/internal/runtime.TracePanic"(%"github.com/goplus/llgo/internal/runtime.iface" %0) {
_llgo_0:
%1 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8
store %"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %1, align 8
%2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %1, i32 0, i32 0
%3 = load ptr, ptr %2, align 8
%4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %3, i32 0, i32 1
%5 = load ptr, ptr %4, align 8
%6 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.Type", ptr %5, i32 0, i32 6
%7 = load i8, ptr %6, align 1
%8 = sext i8 %7 to i64
%9 = icmp eq i64 %8, 24
br i1 %9, label %_llgo_2, label %_llgo_1
_llgo_1: ; preds = %_llgo_2, %_llgo_0
ret void
_llgo_2: ; preds = %_llgo_0
%10 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %1, i32 0, i32 1
%11 = load ptr, ptr %10, align 8
%12 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %11, i32 0, i32 1
%13 = load i64, ptr %12, align 4
%14 = add i64 %13, 1
%15 = alloca i8, i64 %14, align 1
%16 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %11, align 8
%17 = call ptr @"github.com/goplus/llgo/internal/runtime.CStrCopy"(ptr %15, %"github.com/goplus/llgo/internal/runtime.String" %16)
%18 = call i32 (ptr, ...) @printf(ptr @1, ptr %17)
br label %_llgo_1
}
define ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 %0) { define ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 %0) {
_llgo_0: _llgo_0:
%1 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16) %1 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 48)
%2 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.Type", ptr %1, i32 0, i32 0 %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 %3 = getelementptr inbounds i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 %0
%4 = load i64, ptr %3, align 4 %4 = load i64, ptr %3, align 4
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.Type", ptr %1, i32 0, i32 6 %5 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.Type", ptr %1, i32 0, i32 2
%6 = trunc i64 %0 to i8 %6 = trunc i64 %0 to i32
%7 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.Type", ptr %1, i32 0, i32 6
%8 = trunc i64 %0 to i8
store i64 %4, ptr %2, align 4 store i64 %4, ptr %2, align 4
store i8 %6, ptr %5, align 1 store i32 %6, ptr %5, align 4
store i8 %8, ptr %7, align 1
ret ptr %1 ret ptr %1
} }
declare i32 @rand()
define void @"github.com/goplus/llgo/internal/runtime.init"() { define void @"github.com/goplus/llgo/internal/runtime.init"() {
_llgo_0: _llgo_0:
%0 = load i1, ptr @"github.com/goplus/llgo/internal/runtime.init$guard", align 1 %0 = load i1, ptr @"github.com/goplus/llgo/internal/runtime.init$guard", align 1
@@ -208,7 +339,7 @@ _llgo_0:
_llgo_1: ; preds = %_llgo_0 _llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"github.com/goplus/llgo/internal/runtime.init$guard", align 1 store i1 true, ptr @"github.com/goplus/llgo/internal/runtime.init$guard", align 1
call void @"github.com/goplus/llgo/internal/abi.init"() call void @"github.com/goplus/llgo/internal/abi.init"()
%1 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16) %1 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 80)
store ptr %1, ptr @"github.com/goplus/llgo/internal/runtime.TyAny", align 8 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 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 8, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 2), align 4
@@ -267,4 +398,25 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void ret void
} }
define i1 @"github.com/goplus/llgo/internal/runtime.isEmpty"(i8 %0) {
_llgo_0:
%1 = icmp ule i8 %0, 1
ret i1 %1
}
define ptr @"github.com/goplus/llgo/internal/runtime.makemap_small"() {
_llgo_0:
%0 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 48)
%1 = call i32 @rand()
%2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.hmap", ptr %0, i32 0, i32 4
store i32 %1, ptr %2, align 4
ret ptr %0
}
declare ptr @malloc(i64)
declare ptr @memcpy(ptr, ptr, i64)
declare i32 @printf(ptr, ...)
declare void @"github.com/goplus/llgo/internal/abi.init"() declare void @"github.com/goplus/llgo/internal/abi.init"()

1726
internal/runtime/map.go Normal file

File diff suppressed because it is too large Load Diff

38
internal/runtime/stubs.go Normal file
View File

@@ -0,0 +1,38 @@
// Copyright 2014 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"
//go:linkname fastrand C.rand
func fastrand() uint32
/* TODO(xsw):
func fastrand() uint32 {
mp := getg().m
// Implement wyrand: https://github.com/wangyi-fudan/wyhash
// Only the platform that math.Mul64 can be lowered
// by the compiler should be in this list.
if goarch.IsAmd64|goarch.IsArm64|goarch.IsPpc64|
goarch.IsPpc64le|goarch.IsMips64|goarch.IsMips64le|
goarch.IsS390x|goarch.IsRiscv64|goarch.IsLoong64 == 1 {
mp.fastrand += 0xa0761d6478bd642f
hi, lo := math.Mul64(mp.fastrand, mp.fastrand^0xe7037ed1a0b428db)
return uint32(hi ^ lo)
}
// Implement xorshift64+: 2 32-bit xorshift sequences added together.
// Shift triplet [17,7,16] was calculated as indicated in Marsaglia's
// Xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf
// This generator passes the SmallCrush suite, part of TestU01 framework:
// http://simul.iro.umontreal.ca/testu01/tu01.html
t := (*[2]uint32)(unsafe.Pointer(&mp.fastrand))
s1, s0 := t[0], t[1]
s1 ^= s1 << 17
s1 = s1 ^ s0 ^ s1>>7 ^ s0>>16
t[0], t[1] = s0, s1
return s0 + s1
}
*/

View File

@@ -16,3 +16,21 @@ import (
type _type = abi.Type type _type = abi.Type
type interfacetype = abi.InterfaceType type interfacetype = abi.InterfaceType
type maptype = abi.MapType
/*
type arraytype = abi.ArrayType
type chantype = abi.ChanType
type slicetype = abi.SliceType
type functype = abi.FuncType
type ptrtype = abi.PtrType
type name = abi.Name
type structtype = abi.StructType
*/

41
internal/runtime/z_c.go Normal file
View File

@@ -0,0 +1,41 @@
/*
* 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"
"github.com/goplus/llgo/internal/runtime/c"
)
// Alloc allocates memory.
func Alloc(size uintptr) unsafe.Pointer {
return c.Malloc(size)
}
// TracePanic prints panic message.
func TracePanic(v Interface) {
kind := abi.Kind(v.tab._type.Kind_)
switch {
case kind == abi.String:
s := (*String)(v.data)
cs := c.Alloca(uintptr(s.len) + 1)
c.Printf(c.Str("panic: %s\n"), CStrCopy(cs, *s))
}
// TODO(xsw): other message type
}

View File

@@ -22,7 +22,7 @@ import (
"github.com/goplus/llgo/internal/abi" "github.com/goplus/llgo/internal/abi"
) )
type Interface = iface // -----------------------------------------------------------------------------
type InterfaceType = abi.InterfaceType type InterfaceType = abi.InterfaceType
@@ -30,31 +30,36 @@ var (
TyAny = &InterfaceType{} TyAny = &InterfaceType{}
) )
// -----------------------------------------------------------------------------
type Interface = iface
func MakeAnyInt(typ *Type, data uintptr) Interface { func MakeAnyInt(typ *Type, data uintptr) Interface {
tab := &itab{inter: TyAny, _type: typ, hash: 0, fun: [1]uintptr{0}}
return Interface{ return Interface{
tab: &itab{inter: TyAny, _type: typ, hash: 0, fun: [1]uintptr{0}}, tab: tab, data: unsafe.Pointer(data),
data: unsafe.Pointer(data),
} }
} }
func MakeAnyString(data string) Interface { func MakeAnyString(data string) Interface {
typ := basicTypes[abi.String]
tab := &itab{inter: TyAny, _type: typ, hash: 0, fun: [1]uintptr{0}}
return Interface{ return Interface{
tab: &itab{inter: TyAny, _type: Basic(abi.String), hash: 0, fun: [1]uintptr{0}}, tab: tab, data: unsafe.Pointer(&data),
data: unsafe.Pointer(&data),
} }
} }
func MakeAny(typ *Type, data unsafe.Pointer) Interface { func MakeAny(typ *Type, data unsafe.Pointer) Interface {
tab := &itab{inter: TyAny, _type: typ, hash: 0, fun: [1]uintptr{0}}
return Interface{ return Interface{
tab: &itab{inter: TyAny, _type: typ, hash: 0, fun: [1]uintptr{0}}, tab: tab, data: data,
data: data,
} }
} }
func MakeInterface(inter *InterfaceType, typ *Type, data unsafe.Pointer) Interface { func MakeInterface(inter *InterfaceType, typ *Type, data unsafe.Pointer) Interface {
tab := &itab{inter: inter, _type: typ, hash: 0, fun: [1]uintptr{0}}
return Interface{ return Interface{
tab: &itab{inter: inter, _type: typ, hash: 0, fun: [1]uintptr{0}}, tab: tab, data: data,
data: data,
} }
} }
@@ -71,3 +76,5 @@ func CheckI2Int(v Interface, t *Type) (uintptr, bool) {
} }
return 0, false return 0, false
} }
// -----------------------------------------------------------------------------

View File

@@ -16,16 +16,10 @@
package runtime package runtime
import "unsafe" // Map represents a Go map.
type Map = hmap
const ( // MakeSmallMap creates a new small map.
LLGoPackage = true func MakeSmallMap() *Map {
) return makemap_small()
//go:linkname Malloc C.malloc
func Malloc(size uintptr) unsafe.Pointer
// Alloc allocates memory.
func Alloc(size uintptr) unsafe.Pointer {
return Malloc(size)
} }

View File

@@ -20,9 +20,11 @@ import (
"unsafe" "unsafe"
) )
// -----------------------------------------------------------------------------
// Slice is the runtime representation of a slice. // Slice is the runtime representation of a slice.
type Slice struct { type Slice struct {
array unsafe.Pointer data unsafe.Pointer
len int len int
cap int cap int
} }
@@ -31,3 +33,20 @@ type Slice struct {
func NilSlice() Slice { func NilSlice() Slice {
return Slice{nil, 0, 0} return Slice{nil, 0, 0}
} }
// NewSlice creates a new slice.
func NewSlice(data unsafe.Pointer, len, cap int) Slice {
return Slice{data, len, cap}
}
// SliceLen returns the length of a slice.
func SliceLen(s Slice) int {
return s.len
}
// SliceData returns the data pointer of a slice.
func SliceData(s Slice) unsafe.Pointer {
return s.data
}
// -----------------------------------------------------------------------------

View File

@@ -18,8 +18,12 @@ package runtime
import ( import (
"unsafe" "unsafe"
"github.com/goplus/llgo/internal/runtime/c"
) )
// -----------------------------------------------------------------------------
// String is the runtime representation of a string. // String is the runtime representation of a string.
// It cannot be used safely or portably and its representation may // It cannot be used safely or portably and its representation may
// change in a later release. // change in a later release.
@@ -35,3 +39,36 @@ type String struct {
func EmptyString() String { func EmptyString() String {
return String{nil, 0} return String{nil, 0}
} }
// NewString creates a new string.
func NewString(data unsafe.Pointer, len int) String {
return String{data, len}
}
// StringLen returns the length of a string.
func StringLen(s Slice) int {
return s.len
}
// StringData returns the data pointer of a string.
func StringData(s String) unsafe.Pointer {
return s.data
}
// -----------------------------------------------------------------------------
// CStrCopy copies a Go string to a C string buffer and returns it.
func CStrCopy(dest unsafe.Pointer, s String) *int8 {
n := s.len
c.Memcpy(dest, s.data, uintptr(n))
arr := (*[1 << 30]int8)(dest)
arr[n] = 0
return (*int8)(dest)
}
func CStrDup(s String) *int8 {
dest := Alloc(uintptr(s.len + 1))
return CStrCopy(dest, s)
}
// -----------------------------------------------------------------------------

View File

@@ -22,6 +22,8 @@ import (
"github.com/goplus/llgo/internal/abi" "github.com/goplus/llgo/internal/abi"
) )
// -----------------------------------------------------------------------------
type Kind = abi.Kind type Kind = abi.Kind
type Type = abi.Type type Type = abi.Type
@@ -74,8 +76,11 @@ var (
) )
func basicType(kind abi.Kind) *Type { func basicType(kind abi.Kind) *Type {
return &abi.Type{ return &Type{
Size_: sizeBasicTypes[kind], Size_: sizeBasicTypes[kind],
Hash: uint32(kind),
Kind_: uint8(kind), Kind_: uint8(kind),
} }
} }
// -----------------------------------------------------------------------------

View File

@@ -22,8 +22,8 @@ import (
"github.com/goplus/llgo/cl/cltest" "github.com/goplus/llgo/cl/cltest"
) )
func TestFromTestcgo(t *testing.T) { func TestFromTestrt(t *testing.T) {
cltest.FromDir(t, "", "../cl/_testcgo", true) cltest.FromDir(t, "", "../cl/_testrt", true)
} }
func TestFromTestdata(t *testing.T) { func TestFromTestdata(t *testing.T) {

View File

@@ -23,7 +23,6 @@ import (
"go/token" "go/token"
"go/types" "go/types"
"log" "log"
"unsafe"
"github.com/goplus/llvm" "github.com/goplus/llvm"
) )
@@ -35,6 +34,13 @@ type Expr struct {
Type Type
} }
var Nil Expr // Zero value is a nil Expr
// IsNil checks if the expression is nil or not.
func (v Expr) IsNil() bool {
return v.Type == nil
}
/* /*
// TypeOf returns the type of the expression. // TypeOf returns the type of the expression.
func (v Expr) TypeOf() types.Type { func (v Expr) TypeOf() types.Type {
@@ -67,35 +73,11 @@ func (p delayExprTy) String() string {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
func llvmValues(vals []Expr) []llvm.Value {
ret := make([]llvm.Value, len(vals))
for i, v := range vals {
ret[i] = v.impl
}
return ret
}
// -----------------------------------------------------------------------------
// Null returns a null constant expression. // 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. // 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()
@@ -113,6 +95,11 @@ func (p Program) IntVal(v uint64, t Type) Expr {
return Expr{ret, t} return Expr{ret, t}
} }
func (p Program) FloatVal(v float64, t Type) Expr {
ret := llvm.ConstFloat(t.ll, v)
return Expr{ret, t}
}
// Val returns a constant expression. // Val returns a constant expression.
func (p Program) Val(v interface{}) Expr { func (p Program) Val(v interface{}) Expr {
switch v := v.(type) { switch v := v.(type) {
@@ -132,7 +119,7 @@ func (p Program) Val(v interface{}) Expr {
// Const returns a constant expression. // 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 prog := b.Prog
if v == nil { if v == nil {
return prog.Null(typ) return prog.Null(typ)
} }
@@ -142,15 +129,37 @@ func (b Builder) Const(v constant.Value, typ Type) Expr {
switch { switch {
case kind == types.Bool: case kind == types.Bool:
return prog.BoolVal(constant.BoolVal(v)) return prog.BoolVal(constant.BoolVal(v))
case kind >= types.Int && kind <= types.Uintptr: case kind >= types.Int && kind <= types.Int64:
if v, exact := constant.Int64Val(v); exact {
return prog.IntVal(uint64(v), typ)
}
case kind >= types.Uint && kind <= types.Uintptr:
if v, exact := constant.Uint64Val(v); exact { if v, exact := constant.Uint64Val(v); exact {
return prog.IntVal(v, typ) return prog.IntVal(v, typ)
} }
case kind == types.Float32 || kind == types.Float64:
if v, exact := constant.Float64Val(v); exact {
return prog.FloatVal(v, typ)
}
case kind == types.String: case kind == types.String:
return prog.StringVal(constant.StringVal(v)) return b.Str(constant.StringVal(v))
} }
} }
panic("todo") panic(fmt.Sprintf("unsupported Const: %v, %v", v, typ.t))
}
// CStr returns a c-style string constant expression.
func (b Builder) CStr(v string) Expr {
return Expr{llvm.CreateGlobalStringPtr(b.impl, v), b.Prog.CStr()}
}
// Str returns a Go string constant expression.
func (b Builder) Str(v string) (ret Expr) {
prog := b.Prog
cstr := b.CStr(v)
ret = b.InlineCall(b.fn.pkg.rtFunc("NewString"), cstr, prog.Val(len(v)))
ret.Type = prog.String()
return
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -277,7 +286,7 @@ func (b Builder) BinOp(op token.Token, x, y Expr) Expr {
} }
return Expr{llvm.CreateBinOp(b.impl, llop, x.impl, y.impl), x.Type} return Expr{llvm.CreateBinOp(b.impl, llop, x.impl, y.impl), x.Type}
case isPredOp(op): // op: == != < <= < >= case isPredOp(op): // op: == != < <= < >=
tret := b.prog.Bool() tret := b.Prog.Bool()
kind := x.kind kind := x.kind
switch kind { switch kind {
case vkSigned: case vkSigned:
@@ -313,12 +322,49 @@ func (b Builder) UnOp(op token.Token, x Expr) Expr {
panic("todo") panic("todo")
} }
// -----------------------------------------------------------------------------
func llvmValues(vals []Expr) []llvm.Value {
ret := make([]llvm.Value, len(vals))
for i, v := range vals {
ret[i] = v.impl
}
return ret
}
func llvmBlocks(bblks []BasicBlock) []llvm.BasicBlock {
ret := make([]llvm.BasicBlock, len(bblks))
for i, v := range bblks {
ret[i] = v.impl
}
return ret
}
// Phi represents a phi node.
type Phi struct {
Expr
}
// AddIncoming adds incoming values to a phi node.
func (p Phi) AddIncoming(vals []Expr, bblks []BasicBlock) {
v := llvmValues(vals)
b := llvmBlocks(bblks)
p.impl.AddIncoming(v, b)
}
// Phi returns a phi node.
func (b Builder) Phi(t Type) Phi {
return Phi{Expr{llvm.CreatePHI(b.impl, t.ll), t}}
}
// -----------------------------------------------------------------------------
// 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) 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}
} }
@@ -354,7 +400,7 @@ func (b Builder) FieldAddr(x Expr, idx int) Expr {
if debugInstr { if debugInstr {
log.Printf("FieldAddr %v, %d\n", x.impl, idx) log.Printf("FieldAddr %v, %d\n", x.impl, idx)
} }
prog := b.prog prog := b.Prog
tstruc := prog.Elem(x.Type) tstruc := prog.Elem(x.Type)
telem := prog.Field(tstruc, idx) telem := prog.Field(tstruc, idx)
pt := prog.Pointer(telem) pt := prog.Pointer(telem)
@@ -377,13 +423,86 @@ func (b Builder) IndexAddr(x, idx Expr) Expr {
if debugInstr { if debugInstr {
log.Printf("IndexAddr %v, %v\n", x.impl, idx.impl) log.Printf("IndexAddr %v, %v\n", x.impl, idx.impl)
} }
prog := b.prog prog := b.Prog
telem := prog.Index(x.Type) telem := prog.Index(x.Type)
pt := prog.Pointer(telem) pt := prog.Pointer(telem)
switch x.t.Underlying().(type) {
case *types.Slice:
pkg := b.fn.pkg
ptr := b.InlineCall(pkg.rtFunc("SliceData"), x)
indices := []llvm.Value{idx.impl}
return Expr{llvm.CreateInBoundsGEP(b.impl, telem.ll, ptr.impl, indices), pt}
}
// case *types.Pointer:
indices := []llvm.Value{idx.impl} indices := []llvm.Value{idx.impl}
return Expr{llvm.CreateInBoundsGEP(b.impl, telem.ll, x.impl, indices), pt} return Expr{llvm.CreateInBoundsGEP(b.impl, telem.ll, x.impl, indices), pt}
} }
// The Slice instruction yields a slice of an existing string, slice
// or *array X between optional integer bounds Low and High.
//
// Dynamically, this instruction panics if X evaluates to a nil *array
// pointer.
//
// Type() returns string if the type of X was string, otherwise a
// *types.Slice with the same element type as X.
//
// Pos() returns the ast.SliceExpr.Lbrack if created by a x[:] slice
// operation, the ast.CompositeLit.Lbrace if created by a literal, or
// NoPos if not explicit in the source (e.g. a variadic argument slice).
//
// Example printed form:
//
// t1 = slice t0[1:]
func (b Builder) Slice(x, low, high, max Expr) (ret Expr) {
if debugInstr {
log.Printf("Slice %v, %v, %v\n", x.impl, low.impl, high.impl)
}
prog := b.Prog
pkg := b.fn.pkg
switch t := x.t.Underlying().(type) {
case *types.Pointer:
telem := t.Elem()
switch te := telem.Underlying().(type) {
case *types.Array:
ret.Type = prog.Type(types.NewSlice(te.Elem()))
if low.IsNil() && high.IsNil() && max.IsNil() {
n := prog.Val(int(te.Len()))
ret.impl = b.InlineCall(pkg.rtFunc("NewSlice"), x, n, n).impl
return ret
}
}
}
panic("todo")
}
// -----------------------------------------------------------------------------
// The MakeMap instruction creates a new hash-table-based map object
// and yields a value of kind map.
//
// t is a (possibly named) *types.Map.
//
// Pos() returns the ast.CallExpr.Lparen, if created by make(map), or
// the ast.CompositeLit.Lbrack if created by a literal.
//
// Example printed form:
//
// t1 = make map[string]int t0
// t1 = make StringIntMap t0
func (b Builder) MakeMap(t Type, nReserve Expr) (ret Expr) {
if debugInstr {
log.Printf("MakeMap %v, %v\n", t, nReserve.impl)
}
pkg := b.fn.pkg
ret.Type = t
ret.impl = b.InlineCall(pkg.rtFunc("MakeSmallMap")).impl
// TODO(xsw): nReserve
return
}
// -----------------------------------------------------------------------------
// The Alloc instruction reserves space for a variable of the given type, // The Alloc instruction reserves space for a variable of the given type,
// zero-initializes it, and yields its address. // zero-initializes it, and yields its address.
// //
@@ -407,12 +526,12 @@ func (b Builder) Alloc(t *types.Pointer, heap bool) (ret Expr) {
if debugInstr { if debugInstr {
log.Printf("Alloc %v, %v\n", t, heap) log.Printf("Alloc %v, %v\n", t, heap)
} }
prog := b.prog prog := b.Prog
telem := t.Elem() telem := t.Elem()
if heap { if heap {
pkg := b.fn.pkg pkg := b.fn.pkg
size := unsafe.Sizeof(telem) size := prog.sizs.Sizeof(telem)
ret = b.Call(pkg.rtFunc("Alloc"), prog.Val(size)) ret = b.Call(pkg.rtFunc("Alloc"), prog.Val(uintptr(size)))
} else { } else {
ret.impl = llvm.CreateAlloca(b.impl, prog.Type(telem).ll) ret.impl = llvm.CreateAlloca(b.impl, prog.Type(telem).ll)
} }
@@ -421,6 +540,44 @@ func (b Builder) Alloc(t *types.Pointer, heap bool) (ret Expr) {
return return
} }
// Alloca allocates space for n bytes.
func (b Builder) Alloca(n Expr) (ret Expr) {
if debugInstr {
log.Printf("Alloca %v\n", n.impl)
}
prog := b.Prog
telem := prog.tyInt8()
ret.impl = llvm.CreateArrayAlloca(b.impl, telem, n.impl)
ret.Type = &aType{prog.tyVoidPtr(), types.Typ[types.UnsafePointer], vkPtr}
return
}
/*
// ArrayAlloca reserves space for an array of n elements of type telem.
func (b Builder) ArrayAlloca(telem Type, n Expr) (ret Expr) {
if debugInstr {
log.Printf("ArrayAlloca %v, %v\n", telem.t, n.impl)
}
ret.impl = llvm.CreateArrayAlloca(b.impl, telem.ll, n.impl)
ret.Type = b.Prog.Pointer(telem)
return
}
*/
// AllocaCStr allocates space for copy it from a Go string.
func (b Builder) AllocaCStr(gostr Expr) (ret Expr) {
if debugInstr {
log.Printf("AllocaCStr %v\n", gostr.impl)
}
pkg := b.fn.pkg
n := b.InlineCall(pkg.rtFunc("StringLen"), gostr)
n1 := b.BinOp(token.ADD, n, b.Prog.Val(1))
cstr := b.Alloca(n1)
return b.InlineCall(pkg.rtFunc("CStrCopy"), cstr, gostr)
}
// -----------------------------------------------------------------------------
// The ChangeType instruction applies to X a value-preserving type // The ChangeType instruction applies to X a value-preserving type
// change to Type(). // change to Type().
// //
@@ -452,7 +609,7 @@ func (b Builder) ChangeType(t Type, x Expr) (ret Expr) {
switch typ.(type) { switch typ.(type) {
default: default:
ret.impl = b.impl.CreateBitCast(x.impl, t.ll, "bitCast") ret.impl = b.impl.CreateBitCast(x.impl, t.ll, "bitCast")
ret.Type = b.prog.Type(typ) ret.Type = b.Prog.Type(typ)
return return
} }
} }
@@ -488,7 +645,7 @@ func (b Builder) ChangeType(t Type, x Expr) (ret Expr) {
// t1 = convert []byte <- string (t0) // t1 = convert []byte <- string (t0)
func (b Builder) Convert(t Type, x Expr) (ret Expr) { func (b Builder) Convert(t Type, x Expr) (ret Expr) {
typ := t.t typ := t.t
ret.Type = b.prog.Type(typ) ret.Type = b.Prog.Type(typ)
switch und := typ.Underlying().(type) { switch und := typ.Underlying().(type) {
case *types.Basic: case *types.Basic:
kind := und.Kind() kind := und.Kind()
@@ -546,17 +703,24 @@ func (b Builder) MakeInterface(inter types.Type, x Expr, mayDelay bool) (ret Exp
if debugInstr { if debugInstr {
log.Printf("MakeInterface %v, %v\n", inter, x.impl) log.Printf("MakeInterface %v, %v\n", inter, x.impl)
} }
t := inter.Underlying().(*types.Interface) tiund := inter.Underlying().(*types.Interface)
isAny := t.Empty() isAny := tiund.Empty()
fnDo := func() Expr { fnDo := func() Expr {
prog := b.Prog
pkg := b.fn.pkg pkg := b.fn.pkg
switch x.kind { tinter := prog.Type(inter)
case vkSigned, vkUnsigned, vkFloat: switch tx := x.t.Underlying().(type) {
fn := pkg.rtFunc("MakeAnyInt") case *types.Basic:
return b.InlineCall(fn, x) kind := tx.Kind()
case vkString: switch {
fn := pkg.rtFunc("MakeAnyString") case kind >= types.Int && kind <= types.Uintptr:
return b.InlineCall(fn, x) t := b.InlineCall(pkg.rtFunc("Basic"), prog.Val(int(kind)))
tptr := prog.Uintptr()
vptr := Expr{llvm.CreateIntCast(b.impl, x.impl, tptr.ll), tptr}
return Expr{b.InlineCall(pkg.rtFunc("MakeAnyInt"), t, vptr).impl, tinter}
case kind == types.String:
return Expr{b.InlineCall(pkg.rtFunc("MakeAnyString"), x).impl, tinter}
}
} }
panic("todo") panic("todo")
} }
@@ -624,7 +788,7 @@ func (b Builder) TypeAssert(x Expr, assertedTyp Type, commaOk bool) (ret Expr) {
default: default:
panic("todo") panic("todo")
} }
typ := b.InlineCall(pkg.rtFunc("Basic"), b.prog.Val(int(kind))) typ := b.InlineCall(pkg.rtFunc("Basic"), b.Prog.Val(int(kind)))
return b.InlineCall(fn, x, typ) return b.InlineCall(fn, x, typ)
} }
panic("todo") panic("todo")
@@ -659,7 +823,7 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
} }
switch t := fn.t.(type) { switch t := fn.t.(type) {
case *types.Signature: case *types.Signature:
ret.Type = b.prog.retType(t) ret.Type = b.Prog.retType(t)
default: default:
panic("todo") panic("todo")
} }
@@ -674,6 +838,16 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
// `fn` indicates the function: one of the built-in functions from the // `fn` indicates the function: one of the built-in functions from the
// Go spec (excluding "make" and "new"). // Go spec (excluding "make" and "new").
func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) { func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
switch fn {
case "len":
if len(args) == 1 {
arg := args[0]
switch arg.t.Underlying().(type) {
case *types.Slice:
return b.InlineCall(b.fn.pkg.rtFunc("SliceLen"), arg)
}
}
}
panic("todo") panic("todo")
} }

View File

@@ -19,6 +19,7 @@ package ssa
import ( import (
"go/constant" "go/constant"
"go/types" "go/types"
"runtime"
"github.com/goplus/llvm" "github.com/goplus/llvm"
"golang.org/x/tools/go/types/typeutil" "golang.org/x/tools/go/types/typeutil"
@@ -97,6 +98,7 @@ func Initialize(flags InitFlags) {
type aProgram struct { type aProgram struct {
ctx llvm.Context ctx llvm.Context
typs typeutil.Map typs typeutil.Map
sizs types.Sizes
rt *types.Package rt *types.Package
rtget func() *types.Package rtget func() *types.Package
@@ -117,6 +119,7 @@ type aProgram struct {
rtStringTy llvm.Type rtStringTy llvm.Type
rtIfaceTy llvm.Type rtIfaceTy llvm.Type
rtSliceTy llvm.Type rtSliceTy llvm.Type
rtMapTy llvm.Type
anyTy Type anyTy Type
voidTy Type voidTy Type
@@ -138,11 +141,16 @@ func NewProgram(target *Target) Program {
if target == nil { if target == nil {
target = &Target{} target = &Target{}
} }
arch := target.GOARCH
if arch == "" {
arch = runtime.GOARCH
}
ctx := llvm.NewContext() ctx := llvm.NewContext()
sizes := types.SizesFor("gc", arch)
// TODO(xsw): Finalize may cause panic, so comment it. // TODO(xsw): Finalize may cause panic, so comment it.
// ctx.Finalize() // 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, sizs: sizes, target: target, td: td}
} }
// SetRuntime sets the runtime. // SetRuntime sets the runtime.
@@ -184,6 +192,13 @@ func (p Program) rtIface() llvm.Type {
return p.rtIfaceTy return p.rtIfaceTy
} }
func (p Program) rtMap() llvm.Type {
if p.rtMapTy.IsNil() {
p.rtMapTy = p.rtType("Map").ll
}
return p.rtMapTy
}
func (p Program) rtSlice() llvm.Type { func (p Program) rtSlice() llvm.Type {
if p.rtSliceTy.IsNil() { if p.rtSliceTy.IsNil() {
p.rtSliceTy = p.rtType("Slice").ll p.rtSliceTy = p.rtType("Slice").ll
@@ -225,7 +240,7 @@ func (p Program) Bool() Type {
return p.boolTy return p.boolTy
} }
func (p Program) CString() Type { func (p Program) CStr() Type {
if p.cstrTy == nil { // *int8 if p.cstrTy == nil { // *int8
p.cstrTy = p.Type(types.NewPointer(types.Typ[types.Int8])) p.cstrTy = p.Type(types.NewPointer(types.Typ[types.Int8]))
} }

View File

@@ -50,7 +50,7 @@ func (p BasicBlock) Index() int {
type aBuilder struct { type aBuilder struct {
impl llvm.Builder impl llvm.Builder
fn Function fn Function
prog Program Prog Program
} }
// Builder represents a builder for creating instructions in a function. // Builder represents a builder for creating instructions in a function.
@@ -73,7 +73,14 @@ func (b Builder) Panic(v Expr) {
if debugInstr { if debugInstr {
log.Printf("Panic %v\n", v.impl) log.Printf("Panic %v\n", v.impl)
} }
b.impl.CreateUnreachable() // TODO(xsw): pass v pkg := b.fn.pkg
b.Call(pkg.rtFunc("TracePanic"), v)
b.impl.CreateUnreachable()
}
// Unreachable emits an unreachable instruction.
func (b Builder) Unreachable() {
b.impl.CreateUnreachable()
} }
// Return emits a return instruction. // Return emits a return instruction.
@@ -121,4 +128,21 @@ func (b Builder) If(cond Expr, thenb, elseb BasicBlock) {
b.impl.CreateCondBr(cond.impl, thenb.impl, elseb.impl) b.impl.CreateCondBr(cond.impl, thenb.impl, elseb.impl)
} }
// The MapUpdate instruction updates the association of Map[Key] to
// Value.
//
// Pos() returns the ast.KeyValueExpr.Colon or ast.IndexExpr.Lbrack,
// if explicit in the source.
//
// Example printed form:
//
// t0[t1] = t2
func (b Builder) MapUpdate(m, k, v Expr) {
if debugInstr {
log.Printf("MapUpdate %v[%v] = %v\n", m.impl, k.impl, v.impl)
}
// TODO(xsw)
// panic("todo")
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@@ -104,6 +104,10 @@ type aType struct {
type Type = *aType type Type = *aType
func (p Program) Slice(typ Type) Type {
return p.Type(types.NewSlice(typ.t))
}
func (p Program) Pointer(typ Type) Type { func (p Program) Pointer(typ Type) Type {
return p.Type(types.NewPointer(typ.t)) return p.Type(types.NewPointer(typ.t))
} }
@@ -252,6 +256,7 @@ func (p Program) toLLVMType(typ types.Type) Type {
case *types.Slice: case *types.Slice:
return &aType{p.rtSlice(), typ, vkInvalid} return &aType{p.rtSlice(), typ, vkInvalid}
case *types.Map: case *types.Map:
return &aType{p.rtMap(), typ, vkInvalid}
case *types.Struct: case *types.Struct:
return p.toLLVMStruct(t) return p.toLLVMStruct(t)
case *types.Named: case *types.Named: