Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa1d0b307b | ||
|
|
8a09d8b442 | ||
|
|
7b99470bfa | ||
|
|
30192da7cf | ||
|
|
66337e0975 | ||
|
|
6e4a44438b | ||
|
|
3cc3b864af | ||
|
|
62f6542ca9 | ||
|
|
8c25848e1b | ||
|
|
e112d8277f | ||
|
|
014d0262da | ||
|
|
8ae97f73d0 | ||
|
|
666808b427 | ||
|
|
f208db48a1 | ||
|
|
673b9d9a5c | ||
|
|
ed8ffb228b | ||
|
|
d5a3ff6fb9 | ||
|
|
d3fddfb634 | ||
|
|
f7a54e3377 | ||
|
|
d62bf858dd | ||
|
|
ae0906d322 | ||
|
|
c6cb2931e1 | ||
|
|
0eac576171 | ||
|
|
0ee96db260 | ||
|
|
40a9e00d4c | ||
|
|
d8615330ad | ||
|
|
02afd1d73a | ||
|
|
4eedb4fb69 | ||
|
|
2d6869bdbd | ||
|
|
c0a9848cfb | ||
|
|
40cc7b2a85 | ||
|
|
dfaae24fea | ||
|
|
839ad8ba2b | ||
|
|
e757c66354 | ||
|
|
3ec6da002a | ||
|
|
190b029154 | ||
|
|
0bfc269652 | ||
|
|
b5961f0807 | ||
|
|
a792e312db | ||
|
|
04f81f3dbb | ||
|
|
91401c4571 | ||
|
|
18fe26e853 | ||
|
|
f895ca1fe6 | ||
|
|
ad28ed3154 | ||
|
|
f64abf37ab | ||
|
|
acc5de8d14 | ||
|
|
85bb1302ca | ||
|
|
fc893ba498 | ||
|
|
7527b326d7 | ||
|
|
a6d31ad8b8 | ||
|
|
664c3fcce3 | ||
|
|
e1d1d6a2d9 | ||
|
|
8c1b8ad945 | ||
|
|
ae5efdf16c | ||
|
|
2b82af519c | ||
|
|
7a347d4563 | ||
|
|
1610894a80 | ||
|
|
4eb2ddaf15 | ||
|
|
99a86d8d4e | ||
|
|
637db665c3 | ||
|
|
bb1da81a01 | ||
|
|
d4ddc61a9f | ||
|
|
6ebbc92c4f | ||
|
|
b45172bef1 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,6 +8,7 @@
|
|||||||
*.so
|
*.so
|
||||||
*.dylib
|
*.dylib
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
err.log
|
err.log
|
||||||
|
|
||||||
_go/
|
_go/
|
||||||
|
|||||||
57
chore/gentests/gentests.go
Normal file
57
chore/gentests/gentests.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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/")
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
|
||||||
}
|
|
||||||
@@ -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"()
|
||||||
|
|||||||
@@ -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, ...)
|
||||||
|
|||||||
@@ -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"()
|
||||||
|
|||||||
@@ -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"()
|
||||||
|
|||||||
@@ -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"()
|
||||||
|
|||||||
@@ -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"()
|
||||||
|
|||||||
11
cl/_testdata/untyped/in.go
Normal file
11
cl/_testdata/untyped/in.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
const c = 100
|
||||||
|
|
||||||
|
var a float64 = 1
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if c > 100 {
|
||||||
|
a = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
35
cl/_testdata/untyped/out.ll
Normal file
35
cl/_testdata/untyped/out.ll
Normal 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"()
|
||||||
@@ -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
12
cl/_testrt/alloca/in.go
Normal 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
35
cl/_testrt/alloca/out.ll
Normal 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
13
cl/_testrt/allocstr/in.go
Normal 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()))
|
||||||
|
}
|
||||||
50
cl/_testrt/allocstr/out.ll
Normal file
50
cl/_testrt/allocstr/out.ll
Normal 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
13
cl/_testrt/any/in.go
Normal 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))
|
||||||
|
}
|
||||||
@@ -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
11
cl/_testrt/builtin/in.go
Normal 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
62
cl/_testrt/builtin/out.ll
Normal 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
13
cl/_testrt/cstr/in.go
Normal 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
30
cl/_testrt/cstr/out.ll
Normal 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
32
cl/_testrt/gblarray/in.go
Normal 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_)
|
||||||
|
}
|
||||||
71
cl/_testrt/gblarray/out.ll
Normal file
71
cl/_testrt/gblarray/out.ll
Normal 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, ...)
|
||||||
@@ -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
13
cl/_testrt/map/in.go
Normal 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
29
cl/_testrt/map/out.ll
Normal 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
5
cl/_testrt/panic/in.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
panic("panic message")
|
||||||
|
}
|
||||||
39
cl/_testrt/panic/out.ll
Normal file
39
cl/_testrt/panic/out.ll
Normal 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")
|
||||||
@@ -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"()
|
||||||
@@ -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
16
cl/_testrt/sum/in.go
Normal 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
74
cl/_testrt/sum/out.ll
Normal 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")
|
||||||
@@ -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)
|
||||||
14
cl/_testrt/unreachable/in.go
Normal file
14
cl/_testrt/unreachable/in.go
Normal 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"))
|
||||||
|
}
|
||||||
37
cl/_testrt/unreachable/out.ll
Normal file
37
cl/_testrt/unreachable/out.ll
Normal 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, ...)
|
||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
180
cl/compile.go
180
cl/compile.go
@@ -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 := p.compileValue(b, cv)
|
fn, ftype := p.funcOf(cv)
|
||||||
args := p.compileValues(b, call.Args, kind)
|
switch ftype {
|
||||||
ret = b.Call(fn, args...)
|
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)
|
||||||
|
args := p.compileValues(b, call.Args, kind)
|
||||||
|
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")
|
||||||
return fn.Expr
|
/*
|
||||||
|
fn, ftype := p.funcOf(v)
|
||||||
|
if ftype >= llgoInstrBase {
|
||||||
|
panic("can't use llgo instruction as a value")
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
110
cl/import.go
110
cl/import.go
@@ -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
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(v, "llgo.") {
|
||||||
|
return v[5:], llgoInstr
|
||||||
|
}
|
||||||
|
return v, goFunc
|
||||||
}
|
}
|
||||||
return name, true
|
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)
|
||||||
|
}
|
||||||
|
} else if ret = pkg.FuncOf(name); ret == nil {
|
||||||
|
ret = pkg.NewFunc(name, fn.Signature)
|
||||||
}
|
}
|
||||||
return 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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
2
go.mod
@@ -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
6
go.sum
@@ -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
14
internal/abi/map.go
Normal 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.
|
||||||
|
)
|
||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
ssaPkg.WriteTo(os.Stderr)
|
if Verbose {
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|||||||
@@ -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
54
internal/runtime/c/c.go
Normal 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
|
||||||
@@ -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
1726
internal/runtime/map.go
Normal file
File diff suppressed because it is too large
Load Diff
38
internal/runtime/stubs.go
Normal file
38
internal/runtime/stubs.go
Normal 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
|
||||||
|
}
|
||||||
|
*/
|
||||||
@@ -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
41
internal/runtime/z_c.go
Normal 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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
}
|
||||||
@@ -20,14 +20,33 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
// NilSlice returns a nil slice.
|
// NilSlice returns a nil slice.
|
||||||
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
272
ssa/expr.go
272
ssa/expr.go
@@ -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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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]))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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")
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user