Compare commits

..

32 Commits

Author SHA1 Message Date
xushiwei
aa4f518262 Merge pull request #673 from cpunion/libuv-async
Add libuv async
2024-08-07 21:43:50 +08:00
xushiwei
f76fa879fc Merge pull request #676 from luoliwoshang/xtool/ast/funcproto
castdump:funcproto type & computed enum value
2024-08-07 21:42:47 +08:00
luoliwoshang
8d70aba1f5 castdump:funcproto type & enum value 2024-08-07 20:33:35 +08:00
Li Jie
a44bb35aec libuv: add async 2024-08-07 20:24:43 +08:00
xushiwei
4fda2b656f Merge pull request #672 from luoliwoshang/c/clang/type-tree
castdump:array,typedef,pointer,funcproto,enum & builtin type
2024-08-07 19:15:37 +08:00
xushiwei
e626d00fdf Merge pull request #674 from hackerchai/feature/c-calloc
feat(c): Add Calloc func
2024-08-07 18:39:35 +08:00
hackerchai
753dcd3301 feat(c): Add Calloc func 2024-08-07 16:45:17 +08:00
Li Jie
8b5dee510e libuv: add uv_stop 2024-08-07 16:21:12 +08:00
luoliwoshang
9cb73fbf78 castdump:array,typedef,pointer & builtin type 2024-08-07 15:52:26 +08:00
xushiwei
e6b4deb5c4 Merge pull request #657 from hackerchai/fix/c-libuv-missing-func
feat(c/libuv): Add libuv missing funcs & refactor go func style
2024-08-07 15:04:52 +08:00
hackerchai
8848222728 feat(c/libuv): Add GetIoWatcherFd func using LLGoFiles 2024-08-07 14:49:21 +08:00
hackerchai
3cd62994c7 Revert "refactor(c/libuv): Use cgo alias replace struct assertion in fs"
This reverts commit 45ba5b8dc50a13223e05ad673f4e57d7277d3f24.

# Conflicts:
#	c/libuv/net.go
2024-08-07 14:49:20 +08:00
hackerchai
dd93a97790 Revert "feat(c/libuv): Add GetIoWatcherFd func"
This reverts commit 1ce16727b1195a65c8f2c9de07a864ed5e3902ef.

Signed-off-by: hackerchai <i@hackerchai.com>
2024-08-07 14:49:19 +08:00
hackerchai
e40e2d2d14 style(c/libuv): Use go type funcs & update demo(syanc_fs, echo_server) 2024-08-07 14:49:18 +08:00
hackerchai
26f8ce7b5a refactor(c/libuv): Use cgo alias replace struct assertion in fs
refactro(c/libuv): Use cgo alias avoid implicit struct member declaration
2024-08-07 14:49:17 +08:00
hackerchai
9a61e374b5 refactor(c/libuv): Move some func due to libuv doc
doc: https://docs.libuv.org/en/v1.x/
2024-08-07 14:49:16 +08:00
hackerchai
9b12e9819c fix(c/libuv/demo): Fix echo_server stream convert 2024-08-07 14:49:15 +08:00
hackerchai
5d0a91239c feat(c/libuv): Add GetIoWatcherFd func 2024-08-07 14:49:14 +08:00
hackerchai
c848278690 feat(c/libuv): Add uv_close & uv_signal func
Signed-off-by: hackerchai <i@hackerchai.com>

feat(c/libuv): Add uv_signal_stop func

Signed-off-by: hackerchai <i@hackerchai.com>

feat(c/libuv): Add GetIoWatcher, GetFd func & add Io srtuct

Signed-off-by: hackerchai <i@hackerchai.com>

refactor(c/libuv):  Rename some func

refactor(c/libuv): Remove net go wrapper

refactor(c/libuv):  Add GetIoWatcherFd func
2024-08-07 14:49:13 +08:00
luoliwoshang
2ebb929e2c castdump:accessMap 2024-08-07 10:59:27 +08:00
xushiwei
b34334ba93 Merge pull request #669 from visualfc/abimap
ssa: fix abi map init
2024-08-07 07:54:27 +08:00
visualfc
05a01cd803 ssa: fix abi map init 2024-08-06 22:24:21 +08:00
xushiwei
9ac0c06f26 Merge pull request #667 from luoliwoshang/c/clang/type
c/clang:cursor enum & type kind
2024-08-06 22:00:27 +08:00
xushiwei
52af22b0e8 Merge pull request #660 from luoliwoshang/c/clang/fullast
c/clang:full ast dump
2024-08-06 21:56:06 +08:00
luoliwoshang
81cfc73b48 castdump:full ast dump 2024-08-06 21:37:00 +08:00
xushiwei
f892bfccdf Merge pull request #665 from xushiwei/hmac
library: crypto/hmac, internal/fmtsort
2024-08-06 18:56:37 +08:00
xushiwei
dbed8fefac library: crypto/hmac 2024-08-06 18:49:24 +08:00
luoliwoshang
ca14637909 c/clang:type kind 2024-08-06 18:23:31 +08:00
luoliwoshang
7db618fba5 c/clang:cursor enum & access pecifier 2024-08-06 18:23:19 +08:00
xushiwei
29c74c09ce library/README: crypto/hmac, crypto/subtle 2024-08-06 17:19:31 +08:00
xushiwei
a2b5b9f97e library (todo): crypto/hmac, internal/fmtsort 2024-08-06 17:03:22 +08:00
tsingbx
6a05aa4e53 llgo support crypto hmac (#663)
* llgo support crypto/hmac
2024-08-06 16:47:51 +08:00
57 changed files with 3829 additions and 3938 deletions

View File

@@ -312,7 +312,9 @@ Here are the Go packages that can be imported correctly:
* [crypto/sha1](https://pkg.go.dev/crypto/sha1) * [crypto/sha1](https://pkg.go.dev/crypto/sha1)
* [crypto/sha256](https://pkg.go.dev/crypto/sha256) * [crypto/sha256](https://pkg.go.dev/crypto/sha256)
* [crypto/sha512](https://pkg.go.dev/crypto/sha512) (partially) * [crypto/sha512](https://pkg.go.dev/crypto/sha512) (partially)
* [crypto/hmac](https://pkg.go.dev/crypto/hmac) (partially)
* [crypto/rand](https://pkg.go.dev/crypto/rand) (partially) * [crypto/rand](https://pkg.go.dev/crypto/rand) (partially)
* [crypto/subtle](https://pkg.go.dev/crypto/subtle) (partially)
* [regexp](https://pkg.go.dev/regexp) * [regexp](https://pkg.go.dev/regexp)
* [regexp/syntax](https://pkg.go.dev/regexp/syntax) * [regexp/syntax](https://pkg.go.dev/regexp/syntax)
* [go/token](https://pkg.go.dev/go/token) * [go/token](https://pkg.go.dev/go/token)

15
_cmptest/hmacdemo/hmac.go Normal file
View File

@@ -0,0 +1,15 @@
package main
import (
"crypto/hmac"
"crypto/sha1"
"fmt"
"io"
)
func main() {
h := hmac.New(sha1.New, []byte("<key>"))
io.WriteString(h, "The fog is getting thicker!")
io.WriteString(h, "And Leon's getting laaarger!")
fmt.Printf("%x", h.Sum(nil))
}

3
c/c.go
View File

@@ -79,6 +79,9 @@ func AllocaNew[T any]() *T { return nil }
//go:linkname Malloc C.malloc //go:linkname Malloc C.malloc
func Malloc(size uintptr) Pointer func Malloc(size uintptr) Pointer
//go:linkname Calloc C.calloc
func Calloc(num uintptr, size uintptr) Pointer
//go:linkname Free C.free //go:linkname Free C.free
func Free(ptr Pointer) func Free(ptr Pointer)

View File

@@ -1,61 +0,0 @@
package main
import (
"fmt"
"os"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/clang"
)
func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitResult {
depth := *(*c.Uint)(clientData)
printAST(cursor, depth+1)
return clang.ChildVisit_Continue
}
func printAST(cursor clang.Cursor, depth c.Uint) {
cursorKind := cursor.Kind.String()
cursorSpelling := cursor.String()
for i := c.Uint(0); i < depth; i++ {
c.Fputs(c.Str(" "), c.Stdout)
}
c.Printf(c.Str("%s: %s\n"), cursorKind.CStr(), cursorSpelling.CStr())
cursorKind.Dispose()
cursorSpelling.Dispose()
clang.VisitChildren(cursor, visit, c.Pointer(&depth))
}
func main() {
if c.Argc != 2 {
fmt.Fprintln(os.Stderr, "Usage: castdump <headerFile>")
return
}
sourceFile := *c.Advance(c.Argv, 1)
index := clang.CreateIndex(0, 0)
unit := index.ParseTranslationUnit(
sourceFile,
nil, 0,
nil, 0,
clang.TranslationUnit_None,
)
if unit == nil {
println("Unable to parse translation unit. Quitting.")
c.Exit(1)
}
cursor := unit.Cursor()
printAST(cursor, 0)
unit.Dispose()
index.Dispose()
}

View File

@@ -80,7 +80,7 @@ func printFuncInfo(cursor clang.Cursor) {
} }
c.Printf(c.Str("%s\n"), cursorStr.CStr()) c.Printf(c.Str("%s\n"), cursorStr.CStr())
if cursor.Kind == clang.CXXMethod || cursor.Kind == clang.FunctionDecl { if cursor.Kind == clang.CursorCXXMethod || cursor.Kind == clang.CursorFunctionDecl {
c.Printf(c.Str("symbol:%s\n"), symbol.CStr()) c.Printf(c.Str("symbol:%s\n"), symbol.CStr())
typeStr := cursor.ResultType().String() typeStr := cursor.ResultType().String()
@@ -107,19 +107,19 @@ func printFuncInfo(cursor clang.Cursor) {
} }
func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitResult { func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitResult {
if cursor.Kind == clang.MacroDefinition { if cursor.Kind == clang.CursorMacroDefinition {
printMarcoInfo(cursor) printMarcoInfo(cursor)
} else if cursor.Kind == clang.Namespace { } else if cursor.Kind == clang.CursorNamespace {
nameStr := cursor.String() nameStr := cursor.String()
context.setNamespaceName(c.GoString(nameStr.CStr())) context.setNamespaceName(c.GoString(nameStr.CStr()))
clang.VisitChildren(cursor, visit, nil) clang.VisitChildren(cursor, visit, nil)
context.setNamespaceName("") context.setNamespaceName("")
} else if cursor.Kind == clang.ClassDecl { } else if cursor.Kind == clang.CursorClassDecl {
nameStr := cursor.String() nameStr := cursor.String()
context.setClassName(c.GoString(nameStr.CStr())) context.setClassName(c.GoString(nameStr.CStr()))
clang.VisitChildren(cursor, visit, nil) clang.VisitChildren(cursor, visit, nil)
context.setClassName("") context.setClassName("")
} else if cursor.Kind == clang.CXXMethod || cursor.Kind == clang.FunctionDecl { } else if cursor.Kind == clang.CursorCXXMethod || cursor.Kind == clang.CursorFunctionDecl {
printFuncInfo(cursor) printFuncInfo(cursor)
} }

View File

@@ -33,6 +33,24 @@ void wrap_clang_getCursorType(CXCursor *cur, CXType *typ) { *typ = clang_getCurs
void wrap_clang_getCursorResultType(CXCursor *cur, CXType *typ) { *typ = clang_getCursorResultType(*cur); } void wrap_clang_getCursorResultType(CXCursor *cur, CXType *typ) { *typ = clang_getCursorResultType(*cur); }
void wrap_clang_getResultType(CXType *typ, CXType *resultTyp) { *resultTyp = clang_getResultType(*typ); }
int wrap_clang_getNumArgTypes(CXType *typ) { return clang_getNumArgTypes(*typ); }
void wrap_clang_getArgType(CXType *typ, unsigned i, CXType *argTyp) { *argTyp = clang_getArgType(*typ, i); }
long long wrap_clang_getEnumConstantDeclValue(CXCursor *cur) { return clang_getEnumConstantDeclValue(*cur); }
void wrap_clang_getPointeeType(CXType *pointerTyp, CXType *pointeeTyp) {
*pointeeTyp = clang_getPointeeType(*pointerTyp);
}
void wrap_clang_getArrayElementType(CXType *arrayTyp, CXType *elemTyp) {
*elemTyp = clang_getArrayElementType(*arrayTyp);
}
void wrap_clang_getCanonicalType(CXType *typ, CXType *canonicalType) { *canonicalType = clang_getCanonicalType(*typ); }
CXString wrap_clang_getTypeSpelling(CXType *typ) { return clang_getTypeSpelling(*typ); } CXString wrap_clang_getTypeSpelling(CXType *typ) { return clang_getTypeSpelling(*typ); }
CXString wrap_clang_getTokenSpelling(CXTranslationUnit unit, CXToken *token) { CXString wrap_clang_getTokenSpelling(CXTranslationUnit unit, CXToken *token) {
@@ -46,6 +64,10 @@ void wrap_clang_getSpellingLocation(CXSourceLocation *loc, CXFile *file, unsigne
clang_getSpellingLocation(*loc, file, line, column, offset); clang_getSpellingLocation(*loc, file, line, column, offset);
} }
enum CX_CXXAccessSpecifier wrap_clang_getCXXAccessSpecifier(CXCursor *cursor) {
return clang_getCXXAccessSpecifier(*cursor);
}
void wrap_clang_getCursorExtent(CXCursor *cur, CXSourceRange *range) { *range = clang_getCursorExtent(*cur); } void wrap_clang_getCursorExtent(CXCursor *cur, CXSourceRange *range) { *range = clang_getCursorExtent(*cur); }
void wrap_clang_tokenize(CXTranslationUnit unit, CXSourceRange *Range, CXToken **Tokens, unsigned *NumTokens) { void wrap_clang_tokenize(CXTranslationUnit unit, CXSourceRange *Range, CXToken **Tokens, unsigned *NumTokens) {

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,41 @@
package main
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/libuv"
)
func ensure(b bool, msg string) {
if !b {
panic(msg)
}
}
func main() {
loop := libuv.LoopNew()
defer loop.Close()
a := &libuv.Async{}
r := loop.Async(a, func(a *libuv.Async) {
println("async callback")
a.Close(nil) // or loop.Stop()
})
ensure(r == 0, "Async failed")
go func() {
println("begin async task")
c.Usleep(100 * 1000)
println("send async event")
ensure(a.Send() == 0, "Send failed")
}()
loop.Run(libuv.RUN_DEFAULT)
println("done")
}
/*Expected Output:
begin async task
send async event
async callback
done
*/

View File

@@ -31,7 +31,7 @@ func main() {
libuv.FsOpen(loop, &openReq, c.Str("example.txt"), os.O_RDONLY, 0, onOpen) libuv.FsOpen(loop, &openReq, c.Str("example.txt"), os.O_RDONLY, 0, onOpen)
// Run the loop // Run the loop
result := libuv.Run(loop, libuv.RUN_DEFAULT) result := loop.Run(libuv.RUN_DEFAULT)
if result != 0 { if result != 0 {
c.Fprintf(c.Stderr, c.Str("Error in Run: %s\n"), libuv.Strerror(libuv.Errno(result))) c.Fprintf(c.Stderr, c.Str("Error in Run: %s\n"), libuv.Strerror(libuv.Errno(result)))
@@ -43,14 +43,14 @@ func main() {
func onOpen(req *libuv.Fs) { func onOpen(req *libuv.Fs) {
// Check for errors // Check for errors
if libuv.FsGetResult(req) < 0 { if req.GetResult() < 0 {
c.Fprintf(c.Stderr, c.Str("Error opening file: %s\n"), libuv.Strerror(libuv.Errno(libuv.FsGetResult(req)))) c.Fprintf(c.Stderr, c.Str("Error opening file: %s\n"), libuv.Strerror(libuv.Errno(req.GetResult())))
libuv.LoopClose(loop) loop.Close()
return return
} }
// Store the file descriptor // Store the file descriptor
file = libuv.File(libuv.FsGetResult(req)) file = libuv.File(req.GetResult())
// Init buffer // Init buffer
iov = libuv.InitBuf((*c.Char)(unsafe.Pointer(&buffer[0])), c.Uint(unsafe.Sizeof(buffer))) iov = libuv.InitBuf((*c.Char)(unsafe.Pointer(&buffer[0])), c.Uint(unsafe.Sizeof(buffer)))
@@ -68,28 +68,28 @@ func readFile() {
readRes := libuv.FsRead(loop, &readReq, file, &iov, 1, -1, onRead) readRes := libuv.FsRead(loop, &readReq, file, &iov, 1, -1, onRead)
if readRes != 0 { if readRes != 0 {
c.Printf(c.Str("Error in FsRead: %s (code: %d)\n"), libuv.Strerror(libuv.Errno(readRes)), readRes) c.Printf(c.Str("Error in FsRead: %s (code: %d)\n"), libuv.Strerror(libuv.Errno(readRes)), readRes)
libuv.FsReqCleanup(&readReq) readReq.ReqCleanup()
libuv.LoopClose(loop) loop.Close()
} }
} }
func onRead(req *libuv.Fs) { func onRead(req *libuv.Fs) {
// Cleanup the request // Cleanup the request
defer libuv.FsReqCleanup(req) defer req.ReqCleanup()
// Check for errors // Check for errors
if libuv.FsGetResult(req) < 0 { if req.GetResult() < 0 {
c.Fprintf(c.Stderr, c.Str("Read error: %s\n"), libuv.Strerror(libuv.Errno(libuv.FsGetResult(req)))) c.Fprintf(c.Stderr, c.Str("Read error: %s\n"), libuv.Strerror(libuv.Errno(req.GetResult())))
} else if libuv.FsGetResult(req) == 0 { } else if req.GetResult() == 0 {
// Close the file // Close the file
closeRes := libuv.FsClose(loop, &closeReq, libuv.File(libuv.FsGetResult(&openReq)), onClose) closeRes := libuv.FsClose(loop, &closeReq, libuv.File(openReq.GetResult()), onClose)
if closeRes != 0 { if closeRes != 0 {
c.Printf(c.Str("Error in FsClose: %s (code: %d)\n"), libuv.Strerror(libuv.Errno(closeRes)), closeRes) c.Printf(c.Str("Error in FsClose: %s (code: %d)\n"), libuv.Strerror(libuv.Errno(closeRes)), closeRes)
libuv.LoopClose(loop) loop.Close()
return return
} }
} else { } else {
c.Printf(c.Str("Read %d bytes\n"), libuv.FsGetResult(req)) c.Printf(c.Str("Read %d bytes\n"), req.GetResult())
c.Printf(c.Str("Read content: %.*s\n"), libuv.FsGetResult(req), (*c.Char)(unsafe.Pointer(&buffer[0]))) c.Printf(c.Str("Read content: %.*s\n"), req.GetResult(), (*c.Char)(unsafe.Pointer(&buffer[0])))
// Read the file again // Read the file again
readFile() readFile()
} }
@@ -97,8 +97,8 @@ func onRead(req *libuv.Fs) {
func onClose(req *libuv.Fs) { func onClose(req *libuv.Fs) {
// Check for errors // Check for errors
if libuv.FsGetResult(req) < 0 { if req.GetResult() < 0 {
c.Fprintf(c.Stderr, c.Str("Error closing file: %s\n"), libuv.Strerror(libuv.Errno(libuv.FsGetResult(req)))) c.Fprintf(c.Stderr, c.Str("Error closing file: %s\n"), libuv.Strerror(libuv.Errno(req.GetResult())))
} else { } else {
c.Printf(c.Str("\nFile closed successfully.\n")) c.Printf(c.Str("\nFile closed successfully.\n"))
} }
@@ -106,10 +106,10 @@ func onClose(req *libuv.Fs) {
func cleanup() { func cleanup() {
// Cleanup the requests // Cleanup the requests
libuv.FsReqCleanup(&openReq) openReq.ReqCleanup()
libuv.FsReqCleanup(&closeReq) closeReq.ReqCleanup()
// Close the loop // Close the loop
result := libuv.LoopClose(loop) result := loop.Close()
if result != 0 { if result != 0 {
c.Fprintf(c.Stderr, c.Str("Error in LoopClose: %s\n"), libuv.Strerror(libuv.Errno(result))) c.Fprintf(c.Stderr, c.Str("Error in LoopClose: %s\n"), libuv.Strerror(libuv.Errno(result)))
} }

View File

@@ -31,14 +31,14 @@ func main() {
// Bind the server to the specified address and port // Bind the server to the specified address and port
(&server).Bind((*net.SockAddr)(c.Pointer(&addr)), 0) (&server).Bind((*net.SockAddr)(c.Pointer(&addr)), 0)
res := (*libuv.Stream)(&server).Listen(DEFAULT_BACKLOG, OnNewConnection) res := (*libuv.Stream)(unsafe.Pointer(&server)).Listen(DEFAULT_BACKLOG, OnNewConnection)
if res != 0 { if res != 0 {
c.Fprintf(c.Stderr, c.Str("Listen error: %s\n"), libuv.Strerror((libuv.Errno(res)))) c.Fprintf(c.Stderr, c.Str("Listen error: %s\n"), libuv.Strerror(libuv.Errno(res)))
return return
} }
// Start listening for incoming connections // Start listening for incoming connections
libuv.Run(loop, libuv.RUN_DEFAULT) loop.Run(libuv.RUN_DEFAULT)
} }
func FreeWriteReq(req *libuv.Write) { func FreeWriteReq(req *libuv.Write) {
@@ -56,7 +56,7 @@ func AllocBuffer(handle *libuv.Handle, suggestedSize uintptr, buf *libuv.Buf) {
func EchoWrite(req *libuv.Write, status c.Int) { func EchoWrite(req *libuv.Write, status c.Int) {
if status != 0 { if status != 0 {
c.Fprintf(c.Stderr, c.Str("Write error: %s\n"), libuv.Strerror((libuv.Errno(status)))) c.Fprintf(c.Stderr, c.Str("Write error: %s\n"), libuv.Strerror(libuv.Errno(status)))
} }
FreeWriteReq(req) FreeWriteReq(req)
} }
@@ -77,8 +77,8 @@ func EchoRead(client *libuv.Stream, nread c.Long, buf *libuv.Buf) {
} }
if nread < 0 { if nread < 0 {
// Handle read errors and EOF. // Handle read errors and EOF.
if (libuv.Errno)(nread) != libuv.EOF { if libuv.Errno(nread) != libuv.EOF {
c.Fprintf(c.Stderr, c.Str("Read error: %s\n"), libuv.Strerror((libuv.Errno)(nread))) c.Fprintf(c.Stderr, c.Str("Read error: %s\n"), libuv.Strerror(libuv.Errno(nread)))
} }
(*libuv.Handle)(c.Pointer(client)).Close(nil) (*libuv.Handle)(c.Pointer(client)).Close(nil)
} }
@@ -110,9 +110,9 @@ func OnNewConnection(server *libuv.Stream, status c.Int) {
} }
// Accept the new connection and start reading data. // Accept the new connection and start reading data.
if server.Accept((*libuv.Stream)(client)) == 0 { if server.Accept((*libuv.Stream)(unsafe.Pointer(client))) == 0 {
(*libuv.Stream)(client).StartRead(AllocBuffer, EchoRead) (*libuv.Stream)(unsafe.Pointer(client)).StartRead(AllocBuffer, EchoRead)
} else { } else {
(*libuv.Handle)(c.Pointer(client)).Close(nil) (*libuv.Handle)(unsafe.Pointer(client)).Close(nil)
} }
} }

5
c/libuv/_wrap/libuv.c Normal file
View File

@@ -0,0 +1,5 @@
#include <uv.h>
int uv_tcp_get_io_watcher_fd (uv_tcp_t* handle) {
return handle->io_watcher.fd;
}

50
c/libuv/async.go Normal file
View File

@@ -0,0 +1,50 @@
/*
* 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 libuv
import (
_ "unsafe"
"github.com/goplus/llgo/c"
)
// struct uv_async_t
type Async struct {
Handle
// On macOS arm64, sizeof uv_async_t is 128 bytes.
// Handle is 92 bytes, so we need 36 bytes to fill the gap.
// Maybe reserve more for future use.
Unused [36]byte
}
// typedef void (*uv_async_cb)(uv_async_t* handle);
// llgo:type C
type AsyncCb func(*Async)
// int uv_async_init(uv_loop_t*, uv_async_t* async, uv_async_cb async_cb);
//
// llgo:link (*Loop).Async C.uv_async_init
func (loop *Loop) Async(a *Async, cb AsyncCb) c.Int {
return 0
}
// int uv_async_send(uv_async_t* async);
//
// llgo:link (*Async).Send C.uv_async_send
func (a *Async) Send() c.Int {
return 0
}

View File

@@ -106,29 +106,40 @@ type FsPollCb func(handle *FsPoll, status c.Int, events c.Int)
/* Fs related function and method */ /* Fs related function and method */
//go:linkname FsGetType C.uv_fs_get_type // llgo:link (*Fs).GetType C.uv_fs_get_type
func FsGetType(req *Fs) FsType func (req *Fs) GetType() FsType {
return 0
}
//go:linkname FsGetPath C.uv_fs_get_path // llgo:link (*Fs).GetPath C.uv_fs_get_path
func FsGetPath(req *Fs) *c.Char func (req *Fs) GetPath() *c.Char {
return nil
}
//go:linkname FsGetResult C.uv_fs_get_result // llgo:link (*Fs).GetResult C.uv_fs_get_result
func FsGetResult(req *Fs) c.Int func (req *Fs) GetResult() c.Int {
return 0
}
//go:linkname FsGetPtr C.uv_fs_get_ptr // llgo:link (*Fs).GetPtr C.uv_fs_get_ptr
func FsGetPtr(req *Fs) c.Pointer func (req *Fs) GetPtr() c.Pointer {
return nil
}
//go:linkname FsGetSystemError C.uv_fs_get_system_error // llgo:link (*Fs).GetSystemError C.uv_fs_get_system_error
func FsGetSystemError(req *Fs) c.Int func (req *Fs) GetSystemError() c.Int {
return 0
}
//go:linkname FsGetStatBuf C.uv_fs_get_statbuf // llgo:link (*Fs).GetStatBuf C.uv_fs_get_statbuf
func FsGetStatBuf(req *Fs) *Stat func (req *Fs) GetStatBuf() *Stat {
return nil
}
//go:linkname FsReqCleanup C.uv_fs_req_cleanup // llgo:link (*Fs).ReqCleanup C.uv_fs_req_cleanup
func FsReqCleanup(req *Fs) func (req *Fs) ReqCleanup() {
// No return value needed for this method
//go:linkname DefaultLoop C.uv_default_loop }
func DefaultLoop() *Loop
//go:linkname FsOpen C.uv_fs_open //go:linkname FsOpen C.uv_fs_open
func FsOpen(loop *Loop, req *Fs, path *c.Char, flags c.Int, mode c.Int, cb FsCb) c.Int func FsOpen(loop *Loop, req *Fs, path *c.Char, flags c.Int, mode c.Int, cb FsCb) c.Int
@@ -241,32 +252,56 @@ func FsLchown(loop *Loop, req *Fs, path *c.Char, uid c.Int, gid c.Int, cb FsCb)
//go:linkname FsLstat C.uv_fs_lstat //go:linkname FsLstat C.uv_fs_lstat
func FsLstat(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int func FsLstat(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int
// ----------------------------------------------
/* FsEvent related function and method */
//go:linkname FsEventInit C.uv_fs_event_init //go:linkname FsEventInit C.uv_fs_event_init
func FsEventInit(loop *Loop, handle *FsEvent) c.Int func FsEventInit(loop *Loop, handle *FsEvent) c.Int
//go:linkname FsEventStart C.uv_fs_event_start // llgo:link (*FsEvent).Start C.uv_fs_event_start
func FsEventStart(handle *FsEvent, cb FsEventCb, path *c.Char, flags c.Int) c.Int func (handle *FsEvent) Start(cb FsEventCb, path *c.Char, flags c.Int) c.Int {
return 0
}
//go:linkname FsEventStop C.uv_fs_event_stop // llgo:link (*FsEvent).Stop C.uv_fs_event_stop
func FsEventStop(handle *FsEvent) c.Int func (handle *FsEvent) Stop() c.Int {
return 0
}
//go:linkname FsEventClose C.uv_fs_event_close // llgo:link (*FsEvent).Close C.uv_fs_event_close
func FsEventClose(handle *FsEvent) c.Int func (handle *FsEvent) Close() c.Int {
return 0
}
//go:linkname FsEventGetpath C.uv_fs_event_getpath // llgo:link (*FsEvent).Getpath C.uv_fs_event_getpath
func FsEventGetpath(handle *FsEvent) *c.Char func (handle *FsEvent) Getpath() *c.Char {
return nil
}
// ----------------------------------------------
/* FsPoll related function and method */
//go:linkname FsPollInit C.uv_fs_poll_init //go:linkname FsPollInit C.uv_fs_poll_init
func FsPollInit(loop *Loop, handle *FsPoll) c.Int func FsPollInit(loop *Loop, handle *FsPoll) c.Int
//go:linkname FsPollStart C.uv_fs_poll_start // llgo:link (*FsPoll).Start C.uv_fs_poll_start
func FsPollStart(handle *FsPoll, cb FsPollCb, path *c.Char, interval uint) c.Int func (handle *FsPoll) Start(cb FsPollCb, path *c.Char, interval uint) c.Int {
return 0
}
//go:linkname FsPollStop C.uv_fs_poll_stop // llgo:link (*FsPoll).Stop C.uv_fs_poll_stop
func FsPollStop(handle *FsPoll) c.Int func (handle *FsPoll) Stop() c.Int {
return 0
}
//go:linkname FsPollClose C.uv_fs_poll_close // llgo:link (*FsPoll).Close C.uv_fs_poll_close
func FsPollClose(handle *FsPoll) c.Int func (handle *FsPoll) Close() c.Int {
return 0
}
//go:linkname FsPollGetPath C.uv_fs_poll_getpath // llgo:link (*FsPoll).GetPath C.uv_fs_poll_getpath
func FsPollGetPath(handle *FsPoll) *c.Char func (handle *FsPoll) GetPath() *c.Char {
return nil
}

View File

@@ -9,6 +9,7 @@ import (
const ( const (
LLGoPackage = "link: $(pkg-config --libs libuv); -luv" LLGoPackage = "link: $(pkg-config --libs libuv); -luv"
LLGoFiles = "$(pkg-config --cflags libuv): _wrap/libuv.c"
) )
// ---------------------------------------------- // ----------------------------------------------
@@ -103,10 +104,6 @@ type Poll struct {
/* Request types. */ /* Request types. */
type Shutdown struct {
Unused [0]byte
}
type Buf struct { type Buf struct {
Base *c.Char Base *c.Char
Len uintptr Len uintptr
@@ -135,9 +132,6 @@ type GetaddrinfoCb func(req *GetAddrInfo, status c.Int, res *net.AddrInfo)
// llgo:type C // llgo:type C
type GetnameinfoCb func(req *GetNameInfo, status c.Int, hostname *c.Char, service *c.Char) type GetnameinfoCb func(req *GetNameInfo, status c.Int, hostname *c.Char, service *c.Char)
// llgo:type C
type ShutdownCb func(req *Shutdown, status c.Int)
// llgo:type C // llgo:type C
type WalkCb func(handle *Handle, arg c.Pointer) type WalkCb func(handle *Handle, arg c.Pointer)
@@ -160,59 +154,88 @@ func ReplaceAllocator(mallocFunc MallocFunc, reallocFunc ReallocFunc, callocFunc
// ---------------------------------------------- // ----------------------------------------------
// llgo:link (*Shutdown).Shutdown C.uv_shutdown
func (shutdown *Shutdown) Shutdown(stream *Stream, shutdownCb ShutdownCb) c.Int {
return 0
}
// ----------------------------------------------
/* Loop related functions and method. */ /* Loop related functions and method. */
//go:linkname DefaultLoop C.uv_default_loop
func DefaultLoop() *Loop
//go:linkname LoopSize C.uv_loop_size //go:linkname LoopSize C.uv_loop_size
func LoopSize() uintptr func LoopSize() uintptr
//go:linkname Run C.uv_run // llgo:link (*Loop).Run C.uv_run
func Run(loop *Loop, mode RunMode) c.Int func (loop *Loop) Run(mode RunMode) c.Int {
return 0
}
//go:linkname LoopAlive C.uv_loop_alive // llgo:link (*Loop).Alive C.uv_loop_alive
func LoopAlive(loop *Loop) c.Int func (loop *Loop) Alive() c.Int {
return 0
}
//go:linkname LoopClose C.uv_loop_close // void uv_stop(uv_loop_t *loop)
func LoopClose(loop *Loop) c.Int //
// llgo:link (*Loop).Stop C.uv_stop
func (loop *Loop) Stop() {}
//go:linkname LoopConfigure C.uv_loop_configure // llgo:link (*Loop).Close C.uv_loop_close
func LoopConfigure(loop *Loop, option LoopOption, arg c.Int) c.Int func (loop *Loop) Close() c.Int {
return 0
}
//go:linkname LoopDefault C.uv_default_loop // llgo:link (*Loop).Configure C.uv_loop_configure
func LoopDefault() *Loop func (loop *Loop) Configure(option LoopOption, arg c.Int) c.Int {
return 0
}
//go:linkname LoopDelete C.uv_loop_delete // llgo:link LoopDefault C.uv_default_loop
func LoopDelete(loop *Loop) c.Int func LoopDefault() *Loop {
return nil
}
//go:linkname LoopFork C.uv_loop_fork // llgo:link (*Loop).Delete C.uv_loop_delete
func LoopFork(loop *Loop) c.Int func (loop *Loop) Delete() c.Int {
return 0
}
//go:linkname LoopInit C.uv_loop_init // llgo:link (*Loop).Fork C.uv_loop_fork
func LoopInit(loop *Loop) c.Int func (loop *Loop) Fork() c.Int {
return 0
}
//go:linkname LoopNew C.uv_loop_new // llgo:link (*Loop).Init C.uv_loop_init
func LoopNew() *Loop func (loop *Loop) Init() c.Int {
return 0
}
//go:linkname LoopNow C.uv_now // llgo:link LoopNew C.uv_loop_new
func LoopNow(loop *Loop) c.UlongLong func LoopNew() *Loop {
return nil
}
//go:linkname LoopUpdateTime C.uv_update_time // llgo:link (*Loop).Now C.uv_now
func LoopUpdateTime(loop *Loop) func (loop *Loop) Now() c.UlongLong {
return 0
}
//go:linkname LoopBackendFd C.uv_backend_fd // llgo:link (*Loop).UpdateTime C.uv_update_time
func LoopBackendFd(loop *Loop) c.Int func (loop *Loop) UpdateTime() {
// No return value needed for this method
}
//go:linkname LoopBackendTimeout C.uv_backend_timeout // llgo:link (*Loop).BackendFd C.uv_backend_fd
func LoopBackendTimeout(loop *Loop) c.Int func (loop *Loop) BackendFd() c.Int {
return 0
}
//go:linkname LoopWalk C.uv_walk // llgo:link (*Loop).BackendTimeout C.uv_backend_timeout
func LoopWalk(loop *Loop, walkCb WalkCb, arg c.Pointer) func (loop *Loop) BackendTimeout() c.Int {
return 0
}
// llgo:link (*Loop).Walk C.uv_walk
func (loop *Loop) Walk(walkCb WalkCb, arg c.Pointer) {
// No return value needed for this method
}
// ---------------------------------------------- // ----------------------------------------------
@@ -228,11 +251,15 @@ func InitBuf(base *c.Char, len c.Uint) Buf
//go:linkname PollInit C.uv_poll_init //go:linkname PollInit C.uv_poll_init
func PollInit(loop *Loop, handle *Poll, fd OsFd) c.Int func PollInit(loop *Loop, handle *Poll, fd OsFd) c.Int
//go:linkname PollStart C.uv_poll_start
func PollStart(handle *Poll, events c.Int, cb PollCb) c.Int
//go:linkname PollStop C.uv_poll_stop
func PollStop(handle *Poll) c.Int
//go:linkname PollInitSocket C.uv_poll_init_socket //go:linkname PollInitSocket C.uv_poll_init_socket
func PollInitSocket(loop *Loop, handle *Poll, socket c.Int) c.Int func PollInitSocket(loop *Loop, handle *Poll, socket c.Int) c.Int
// llgo:link (*Poll).Start C.uv_poll_start
func (handle *Poll) Start(events c.Int, cb PollCb) c.Int {
return 0
}
// llgo:link (*Poll).Stop C.uv_poll_stop
func (handle *Poll) Stop() c.Int {
return 0
}

View File

@@ -117,6 +117,10 @@ type GetNameInfo struct {
Unused [0]byte Unused [0]byte
} }
type Shutdown struct {
Unused [0]byte
}
// ---------------------------------------------- // ----------------------------------------------
/* Function type */ /* Function type */
@@ -142,10 +146,19 @@ type WriteCb func(req *Write, status c.Int)
// llgo:type C // llgo:type C
type ConnectionCb func(server *Stream, status c.Int) type ConnectionCb func(server *Stream, status c.Int)
// llgo:type C
type ShutdownCb func(req *Shutdown, status c.Int)
// ---------------------------------------------- // ----------------------------------------------
/* Handle related function and method */ /* Handle related function and method */
//go:linkname HandleSize C.uv_handle_size
func HandleSize(handleType HandleType) uintptr
//go:linkname HandleTypeName C.uv_handle_type_name
func HandleTypeName(handleType HandleType) *c.Char
// llgo:link (*Handle).Ref C.uv_ref // llgo:link (*Handle).Ref C.uv_ref
func (handle *Handle) Ref() {} func (handle *Handle) Ref() {}
@@ -157,17 +170,11 @@ func (handle *Handle) HasRef() c.Int {
return 0 return 0
} }
//go:linkname HandleSize C.uv_handle_size
func HandleSize(handleType HandleType) uintptr
// llgo:link (*Handle).GetType C.uv_handle_get_type // llgo:link (*Handle).GetType C.uv_handle_get_type
func (handle *Handle) GetType() HandleType { func (handle *Handle) GetType() HandleType {
return 0 return 0
} }
//go:linkname HandleTypeName C.uv_handle_type_name
func HandleTypeName(handleType HandleType) *c.Char
// llgo:link (*Handle).GetData C.uv_handle_get_data // llgo:link (*Handle).GetData C.uv_handle_get_data
func (handle *Handle) GetData() c.Pointer { func (handle *Handle) GetData() c.Pointer {
return nil return nil
@@ -204,6 +211,21 @@ func (handle *Handle) Fileno(fd *OsFd) c.Int {
return 0 return 0
} }
// llgo:link (*Handle).IsClosing C.uv_is_closing
func (handle *Handle) IsClosing() c.Int {
return 0
}
// llgo:link (*Handle).IsReadable C.uv_is_readable
func (handle *Handle) IsReadable() c.Int {
return 0
}
// llgo:link (*Handle).IsWritable C.uv_is_writable
func (handle *Handle) IsWritable() c.Int {
return 0
}
//go:linkname Pipe C.uv_pipe //go:linkname Pipe C.uv_pipe
func Pipe(fds [2]File, readFlags c.Int, writeFlags c.Int) c.Int { func Pipe(fds [2]File, readFlags c.Int, writeFlags c.Int) c.Int {
return 0 return 0
@@ -214,11 +236,6 @@ func Socketpair(_type c.Int, protocol c.Int, socketVector [2]OsSock, flag0 c.Int
return 0 return 0
} }
// llgo:link (*Handle).IsClosing C.uv_is_closing
func (handle *Handle) IsClosing() c.Int {
return 0
}
// ---------------------------------------------- // ----------------------------------------------
/* Req related function and method */ /* Req related function and method */
@@ -226,6 +243,9 @@ func (handle *Handle) IsClosing() c.Int {
//go:linkname ReqSize C.uv_req_size //go:linkname ReqSize C.uv_req_size
func ReqSize(reqType ReqType) uintptr func ReqSize(reqType ReqType) uintptr
//go:linkname TypeName C.uv_req_type_name
func TypeName(reqType ReqType) *c.Char
// llgo:link (*Req).GetData C.uv_req_get_data // llgo:link (*Req).GetData C.uv_req_get_data
func (req *Req) GetData() c.Pointer { func (req *Req) GetData() c.Pointer {
return nil return nil
@@ -239,9 +259,6 @@ func (req *Req) GetType() ReqType {
return 0 return 0
} }
//go:linkname TypeName C.uv_req_type_name
func TypeName(reqType ReqType) *c.Char
// ---------------------------------------------- // ----------------------------------------------
/* Stream related function and method */ /* Stream related function and method */
@@ -306,6 +323,11 @@ func (stream *Stream) SetBlocking(blocking c.Int) c.Int {
return 0 return 0
} }
//go:linkname StreamShutdown C.uv_shutdown
func StreamShutdown(shutdown *Shutdown, stream *Stream, shutdownCb ShutdownCb) c.Int {
return 0
}
// ---------------------------------------------- // ----------------------------------------------
/* Tcp related function and method */ /* Tcp related function and method */
@@ -356,6 +378,11 @@ func (tcp *Tcp) CloseReset(closeCb CloseCb) c.Int {
return 0 return 0
} }
// llgo:link (*Tcp).GetIoWatcherFd C.uv_tcp_get_io_watcher_fd
func (tcp *Tcp) GetIoWatcherFd() c.Int {
return 0
}
//go:linkname TcpConnect C.uv_tcp_connect //go:linkname TcpConnect C.uv_tcp_connect
func TcpConnect(req *Connect, tcp *Tcp, addr *net.SockAddr, connectCb ConnectCb) c.Int func TcpConnect(req *Connect, tcp *Tcp, addr *net.SockAddr, connectCb ConnectCb) c.Int
@@ -429,9 +456,6 @@ func (udp *Udp) SetTTL(ttl c.Int) c.Int {
return 0 return 0
} }
//go:linkname Send C.uv_udp_send
func Send(req *UdpSend, udp *Udp, bufs *Buf, nbufs c.Uint, addr *net.SockAddr, sendCb UdpSendCb) c.Int
// llgo:link (*Udp).TrySend C.uv_udp_try_send // llgo:link (*Udp).TrySend C.uv_udp_try_send
func (udp *Udp) TrySend(bufs *Buf, nbufs c.Uint, addr *net.SockAddr) c.Int { func (udp *Udp) TrySend(bufs *Buf, nbufs c.Uint, addr *net.SockAddr) c.Int {
return 0 return 0
@@ -462,8 +486,13 @@ func (udp *Udp) GetSendQueueCount() uintptr {
return 0 return 0
} }
//go:linkname Send C.uv_udp_send
func Send(req *UdpSend, udp *Udp, bufs *Buf, nbufs c.Uint, addr *net.SockAddr, sendCb UdpSendCb) c.Int
// ---------------------------------------------- // ----------------------------------------------
/* DNS related function and method */
//go:linkname Ip4Addr C.uv_ip4_addr //go:linkname Ip4Addr C.uv_ip4_addr
func Ip4Addr(ip *c.Char, port c.Int, addr *net.SockaddrIn) c.Int func Ip4Addr(ip *c.Char, port c.Int, addr *net.SockaddrIn) c.Int

View File

@@ -26,8 +26,17 @@ type SignalCb func(handle *Signal, sigNum c.Int)
//go:linkname SignalInit C.uv_signal_init //go:linkname SignalInit C.uv_signal_init
func SignalInit(loop *Loop, handle *Signal) c.Int func SignalInit(loop *Loop, handle *Signal) c.Int
//go:linkname SignalStart C.uv_signal_start // llgo:link (*Signal).Start C.uv_signal_start
func SignalStart(handle *Signal, cb SignalCb, signum c.Int) c.Int func (handle *Signal) Start(cb SignalCb, signum c.Int) c.Int {
return 0
}
//go:linkname SignalStartOneshot C.uv_signal_start_oneshot // llgo:link (*Signal).StartOneshot C.uv_signal_start_oneshot
func SignalStartOneshot(handle *Signal, cb SignalCb, signum c.Int) c.Int func (handle *Signal) StartOneshot(cb SignalCb, signum c.Int) c.Int {
return 0
}
// llgo:link (*Signal).Stop C.uv_signal_stop
func (handle *Signal) Stop() c.Int {
return 0
}

View File

@@ -21,7 +21,6 @@ func main() {
return return
} }
defer ctx.Free() defer ctx.Free()
var ret c.Int = ctx.InitEx(unsafe.Pointer(unsafe.StringData(key)), c.Int(lenKey), openssl.EVP_sha256(), nil) var ret c.Int = ctx.InitEx(unsafe.Pointer(unsafe.StringData(key)), c.Int(lenKey), openssl.EVP_sha256(), nil)
if ret == 0 { if ret == 0 {
c.Fprintf(c.Stderr, c.Str("%s\n"), c.Str("Error initializing HMAC_CTX")) c.Fprintf(c.Stderr, c.Str("%s\n"), c.Str("Error initializing HMAC_CTX"))
@@ -37,9 +36,5 @@ func main() {
c.Fprintf(c.Stderr, c.Str("%s\n"), c.Str("Error finalizing HMAC_CTX")) c.Fprintf(c.Stderr, c.Str("%s\n"), c.Str("Error finalizing HMAC_CTX"))
return return
} }
fmt.Print("HMAC: ") fmt.Printf("HMAC:%x\n", digest[:digestLen])
for i := 0; i < int(digestLen); i++ {
fmt.Printf("%02x", digest[i])
}
fmt.Print("\n")
} }

View File

@@ -6,7 +6,15 @@ import (
"github.com/goplus/llgo/c" "github.com/goplus/llgo/c"
) )
const EVP_MAX_MD_SIZE = 64 /* longest known is SHA512 */ const (
EVP_MAX_MD_SIZE = 64 /* longest known is SHA512 */
)
// -----------------------------------------------------------------------------
type EVP_MD struct {
Unused [0]byte
}
// const EVP_MD *EVP_sha1(void) // const EVP_MD *EVP_sha1(void)
// //
@@ -43,13 +51,7 @@ func EVP_sha384() *EVP_MD
//go:linkname EVP_sha512 C.EVP_sha512 //go:linkname EVP_sha512 C.EVP_sha512
func EVP_sha512() *EVP_MD func EVP_sha512() *EVP_MD
type EVP_MD struct { // -----------------------------------------------------------------------------
Unused [0]byte
}
type EVP_MD_CTX struct {
Unused [0]byte
}
type HMAC_CTX struct { type HMAC_CTX struct {
Unused [0]byte Unused [0]byte
@@ -63,30 +65,38 @@ func NewHMAC_CTX() *HMAC_CTX
// OSSL_DEPRECATEDIN_3_0 void HMAC_CTX_free(HMAC_CTX *ctx); // OSSL_DEPRECATEDIN_3_0 void HMAC_CTX_free(HMAC_CTX *ctx);
// //
// llgo:link (*HMAC_CTX).Free C.HMAC_CTX_free // llgo:link (*HMAC_CTX).Free C.HMAC_CTX_free
func (c *HMAC_CTX) Free() {} func (ctx *HMAC_CTX) Free() {}
// OSSL_DEPRECATEDIN_3_0 size_t HMAC_size(const HMAC_CTX *e); // OSSL_DEPRECATEDIN_3_0 size_t HMAC_size(const HMAC_CTX *e);
// //
// llgo:link (*HMAC_CTX).Size C.HMAC_size // llgo:link (*HMAC_CTX).Size C.HMAC_size
func (c *HMAC_CTX) Size() uintptr { return 0 } func (ctx *HMAC_CTX) Size() uintptr { return 0 }
// OSSL_DEPRECATEDIN_3_0 int HMAC_CTX_reset(HMAC_CTX *ctx); // OSSL_DEPRECATEDIN_3_0 int HMAC_CTX_reset(HMAC_CTX *ctx);
// //
// llgo:link (*HMAC_CTX).Reset C.HMAC_CTX_reset // llgo:link (*HMAC_CTX).Reset C.HMAC_CTX_reset
func (c *HMAC_CTX) Reset() c.Int { return 0 } func (ctx *HMAC_CTX) Reset() c.Int { return 0 }
// OSSL_DEPRECATEDIN_1_1_0 __owur int HMAC_Init(HMAC_CTX *ctx, // OSSL_DEPRECATEDIN_1_1_0 __owur int HMAC_Init(HMAC_CTX *ctx,
// const void *key, int len, // const void *key, int len,
// const EVP_MD *md); // const EVP_MD *md);
// //
// llgo:link (*HMAC_CTX).Init C.HMAC_Init // llgo:link (*HMAC_CTX).Init C.HMAC_Init
func (c *HMAC_CTX) Init(key unsafe.Pointer, len c.Int, md *EVP_MD) c.Int { return 0 } func (ctx *HMAC_CTX) Init(key unsafe.Pointer, len c.Int, md *EVP_MD) c.Int { return 0 }
func (ctx *HMAC_CTX) InitBytes(key []byte, md *EVP_MD) c.Int {
return ctx.Init(unsafe.Pointer(unsafe.SliceData(key)), c.Int(len(key)), md)
}
func (ctx *HMAC_CTX) InitString(key string, md *EVP_MD) c.Int {
return ctx.Init(unsafe.Pointer(unsafe.StringData(key)), c.Int(len(key)), md)
}
// OSSL_DEPRECATEDIN_3_0 int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len, // OSSL_DEPRECATEDIN_3_0 int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len,
// const EVP_MD *md, ENGINE *impl); // const EVP_MD *md, ENGINE *impl);
// //
// llgo:link (*HMAC_CTX).InitEx C.HMAC_Init_ex // llgo:link (*HMAC_CTX).InitEx C.HMAC_Init_ex
func (c *HMAC_CTX) InitEx(key unsafe.Pointer, len c.Int, md *EVP_MD, impl unsafe.Pointer) c.Int { func (ctx *HMAC_CTX) InitEx(key unsafe.Pointer, len c.Int, md *EVP_MD, impl unsafe.Pointer) c.Int {
return 0 return 0
} }
@@ -94,28 +104,30 @@ func (c *HMAC_CTX) InitEx(key unsafe.Pointer, len c.Int, md *EVP_MD, impl unsafe
// size_t len); // size_t len);
// //
// llgo:link (*HMAC_CTX).Update C.HMAC_Update // llgo:link (*HMAC_CTX).Update C.HMAC_Update
func (c *HMAC_CTX) Update(data unsafe.Pointer, len uintptr) c.Int { return 0 } func (ctx *HMAC_CTX) Update(data unsafe.Pointer, len uintptr) c.Int { return 0 }
func (c *HMAC_CTX) UpdateBytes(data []byte) c.Int { func (ctx *HMAC_CTX) UpdateBytes(data []byte) c.Int {
return c.Update(unsafe.Pointer(unsafe.SliceData(data)), uintptr(len(data))) return ctx.Update(unsafe.Pointer(unsafe.SliceData(data)), uintptr(len(data)))
} }
func (c *HMAC_CTX) UpdateString(data string) c.Int { func (ctx *HMAC_CTX) UpdateString(data string) c.Int {
return c.Update(unsafe.Pointer(unsafe.StringData(data)), uintptr(len(data))) return ctx.Update(unsafe.Pointer(unsafe.StringData(data)), uintptr(len(data)))
} }
// OSSL_DEPRECATEDIN_3_0 int HMAC_Final(HMAC_CTX *ctx, unsigned char *md, // OSSL_DEPRECATEDIN_3_0 int HMAC_Final(HMAC_CTX *ctx, unsigned char *md,
// unsigned int *len); // unsigned int *len);
// //
// llgo:link (*HMAC_CTX).Final C.HMAC_Final // llgo:link (*HMAC_CTX).Final C.HMAC_Final
func (c *HMAC_CTX) Final(md *byte, len *c.Uint) c.Int { return 0 } func (ctx *HMAC_CTX) Final(md *byte, len *c.Uint) c.Int { return 0 }
// OSSL_DEPRECATEDIN_3_0 __owur int HMAC_CTX_copy(HMAC_CTX *dctx, HMAC_CTX *sctx); // OSSL_DEPRECATEDIN_3_0 __owur int HMAC_CTX_copy(HMAC_CTX *dctx, HMAC_CTX *sctx);
// //
// llgo:link (*HMAC_CTX).Copy C.HMAC_CTX_copy // llgo:link (*HMAC_CTX).Copy C.HMAC_CTX_copy
func (c *HMAC_CTX) Copy(sctx *HMAC_CTX) c.Int { return 0 } func (ctx *HMAC_CTX) Copy(sctx *HMAC_CTX) c.Int { return 0 }
// OSSL_DEPRECATEDIN_3_0 void HMAC_CTX_set_flags(HMAC_CTX *ctx, unsigned long flags); // OSSL_DEPRECATEDIN_3_0 void HMAC_CTX_set_flags(HMAC_CTX *ctx, unsigned long flags);
// //
// llgo:link (*HMAC_CTX).SetFlags C.HMAC_CTX_set_flags // llgo:link (*HMAC_CTX).SetFlags C.HMAC_CTX_set_flags
func (c *HMAC_CTX) SetFlags(flags c.Ulong) {} func (ctx *HMAC_CTX) SetFlags(flags c.Ulong) {}
// -----------------------------------------------------------------------------

View File

@@ -0,0 +1,217 @@
package main
import (
"fmt"
"os"
"strings"
"unsafe"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/clang"
)
type Data struct {
Depth c.Uint
Unit *clang.TranslationUnit
}
var accessMap = map[clang.CXXAccessSpecifier]string{
clang.CXXInvalidAccessSpecifier: "invalid",
clang.CXXPublic: "public",
clang.CXXProtected: "protected",
clang.CXXPrivate: "private",
}
func printIndent(depth c.Uint) {
fmt.Print(strings.Repeat(" ", int(depth)))
}
func accessToString(spec clang.CXXAccessSpecifier) string {
if str, ok := accessMap[spec]; ok {
return str
}
return "unknown"
}
func visit(cursor, parent clang.Cursor, ClientData c.Pointer) clang.ChildVisitResult {
data := (*Data)(ClientData)
printAST(cursor, data)
return clang.ChildVisit_Continue
}
func printType(t clang.Type, data *Data) {
printIndent(data.Depth)
typeSpell := t.String()
typeKind := t.Kind.String()
if t.Kind == clang.TypeInvalid {
} else if t.Kind == clang.TypeUnexposed {
c.Printf(c.Str("<UnexposedType|%s>: %s\n"), typeKind.CStr(), typeSpell.CStr())
} else if t.Kind >= clang.TypeFirstBuiltin && t.Kind <= clang.TypeLastBuiltin {
c.Printf(c.Str("<BuiltinType|%s>: %s\n"), typeKind.CStr(), typeSpell.CStr())
} else if t.Kind > clang.TypeComplex {
c.Printf(c.Str("<ComplexType|%s>: %s\n"), typeKind.CStr(), typeSpell.CStr())
}
data.Depth++
switch t.Kind {
case clang.TypePointer:
printType(t.PointeeType(), data)
case clang.TypeIncompleteArray, clang.TypeVariableArray, clang.TypeDependentSizedArray, clang.TypeConstantArray:
printType(t.ArrayElementType(), data)
case clang.TypeTypedef:
printType(t.CanonicalType(), data)
case clang.TypeFunctionProto:
printType(t.ResultType(), data)
for i := 0; i < int(t.NumArgTypes()); i++ {
printType(t.ArgType(c.Uint(i)), data)
}
}
data.Depth--
typeKind.Dispose()
typeSpell.Dispose()
}
func printLocation(cursor clang.Cursor) {
loc := cursor.Location()
var file clang.File
var line, column c.Uint
loc.SpellingLocation(&file, &line, &column, nil)
filename := file.FileName()
defer filename.Dispose()
c.Printf(c.Str("(Loc:%s:%d:%d)\n"), filename.CStr(), line, column)
}
func printAccess(cursor clang.Cursor) {
kind := cursor.Kind.String()
spell := cursor.String()
defer kind.Dispose()
defer spell.Dispose()
c.Printf(c.Str("%s: %s %s"), kind.CStr(), spell.CStr(), c.AllocaCStr(accessToString(cursor.CXXAccessSpecifier())))
printLocation(cursor)
}
func printMacro(cursor clang.Cursor, unit *clang.TranslationUnit) {
kind := cursor.Kind.String()
defer kind.Dispose()
c.Printf(c.Str("%s: "), kind.CStr())
ran := cursor.Extent()
var numTokens c.Uint
var tokens *clang.Token
unit.Tokenize(ran, &tokens, &numTokens)
tokensSlice := unsafe.Slice(tokens, int(numTokens))
for _, tok := range tokensSlice {
tokStr := unit.Token(tok)
c.Printf(c.Str("%s "), tokStr.CStr())
tokStr.Dispose()
}
printLocation(cursor)
}
func printFunc(cursor clang.Cursor, data *Data) {
kind := cursor.Kind.String()
spell := cursor.String()
symbol := cursor.Mangling()
defer symbol.Dispose()
defer kind.Dispose()
defer spell.Dispose()
c.Printf(c.Str("%s: %s (Symbol: %s)"), kind.CStr(), spell.CStr(), symbol.CStr())
printLocation(cursor)
printType(cursor.Type(), data)
}
func printEnumConstant(cursor clang.Cursor) {
kind := cursor.Kind.String()
spell := cursor.String()
defer kind.Dispose()
defer spell.Dispose()
c.Printf(c.Str("%s: %s:%lld"), kind.CStr(), spell.CStr(), cursor.EnumConstantDeclValue())
printLocation(cursor)
}
func printDefault(cursor clang.Cursor, data *Data) {
kind := cursor.Kind.String()
spell := cursor.String()
defer kind.Dispose()
defer spell.Dispose()
// node which has type
if cursor.Type().Kind != clang.TypeInvalid {
c.Printf(c.Str("%s: %s"), kind.CStr(), spell.CStr())
printLocation(cursor)
printType(cursor.Type(), data)
} else {
c.Printf(c.Str("%s: %s\n"), kind.CStr(), spell.CStr())
}
}
func printAST(cursor clang.Cursor, data *Data) {
kind := cursor.Kind.String()
spell := cursor.String()
printIndent(data.Depth)
switch cursor.Kind {
case clang.CursorCXXAccessSpecifier:
printAccess(cursor)
case clang.CursorMacroDefinition:
printMacro(cursor, data.Unit)
case clang.CursorFunctionDecl, clang.CursorCXXMethod, clang.CursorConstructor, clang.CursorDestructor:
printFunc(cursor, data)
case clang.CursorEnumConstantDecl:
printEnumConstant(cursor)
default:
printDefault(cursor, data)
}
data.Depth++
clang.VisitChildren(cursor, visit, c.Pointer(data))
data.Depth--
kind.Dispose()
spell.Dispose()
}
func main() {
if c.Argc != 2 {
fmt.Fprintln(os.Stderr, "Usage: castdump <headerFile>")
return
}
args := make([]*c.Char, 3)
args[0] = c.Str("-x")
args[1] = c.Str("c++")
args[2] = c.Str("-std=c++11")
sourceFile := *c.Advance(c.Argv, 1)
index := clang.CreateIndex(0, 0)
unit := index.ParseTranslationUnit(
sourceFile,
unsafe.SliceData(args), 3,
nil, 0,
clang.DetailedPreprocessingRecord,
)
defer index.Dispose()
defer unit.Dispose()
if unit == nil {
println("Unable to parse translation unit. Quitting.")
c.Exit(1)
}
cursor := unit.Cursor()
Data := &Data{
Depth: 0,
Unit: unit,
}
printAST(cursor, Data)
}

View File

@@ -1,27 +0,0 @@
package async
import (
"github.com/goplus/llgo/x/async"
)
func GenInts() (co *async.Promise[int]) {
co.Yield(1)
co.Yield(2)
co.Yield(3)
return
}
func WrapGenInts() *async.Promise[int] {
return GenInts()
}
func UseGenInts() int {
co := WrapGenInts()
r := 0
for !co.Done() {
v := co.Value()
r += v
co.Next()
}
return r
}

View File

@@ -1,201 +0,0 @@
; ModuleID = 'async'
source_filename = "async"
%"github.com/goplus/llgo/x/async.Promise[int]" = type { ptr, i64 }
@"async.init$guard" = global i1 false, align 1
define ptr @async.GenInts() presplitcoroutine {
entry:
%id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
%frame.size = call i64 @llvm.coro.size.i64()
%alloc.size = add i64 16, %frame.size
%promise = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 %alloc.size)
%need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
br i1 %need.dyn.alloc, label %alloc, label %_llgo_5
alloc: ; preds = %entry
%0 = getelementptr ptr, ptr %promise, i64 16
br label %_llgo_5
clean: ; preds = %_llgo_8, %_llgo_7, %_llgo_6, %_llgo_5
%1 = call ptr @llvm.coro.free(token %id, ptr %hdl)
br label %suspend
suspend: ; preds = %_llgo_8, %_llgo_7, %_llgo_6, %_llgo_5, %clean
%2 = call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
ret ptr %promise
trap: ; preds = %_llgo_8
call void @llvm.trap()
unreachable
_llgo_5: ; preds = %alloc, %entry
%frame = phi ptr [ null, %entry ], [ %0, %alloc ]
%hdl = call ptr @llvm.coro.begin(token %id, ptr %frame)
store ptr %hdl, ptr %promise, align 8
call void @"github.com/goplus/llgo/x/async.(*Promise).setValue[int]"(ptr %promise, i64 1)
%3 = call i8 @llvm.coro.suspend(token %id, i1 false)
switch i8 %3, label %suspend [
i8 0, label %_llgo_6
i8 1, label %clean
]
_llgo_6: ; preds = %_llgo_5
call void @"github.com/goplus/llgo/x/async.(*Promise).setValue[int]"(ptr %promise, i64 2)
%4 = call i8 @llvm.coro.suspend(token %id, i1 false)
switch i8 %4, label %suspend [
i8 0, label %_llgo_7
i8 1, label %clean
]
_llgo_7: ; preds = %_llgo_6
call void @"github.com/goplus/llgo/x/async.(*Promise).setValue[int]"(ptr %promise, i64 3)
%5 = call i8 @llvm.coro.suspend(token %id, i1 false)
switch i8 %5, label %suspend [
i8 0, label %_llgo_8
i8 1, label %clean
]
_llgo_8: ; preds = %_llgo_7
%6 = call i8 @llvm.coro.suspend(token %id, i1 true)
switch i8 %6, label %suspend [
i8 0, label %trap
i8 1, label %clean
]
}
define i64 @async.UseGenInts() {
_llgo_0:
%0 = call ptr @async.WrapGenInts()
br label %_llgo_3
_llgo_1: ; preds = %_llgo_3
%1 = call i64 @"github.com/goplus/llgo/x/async.(*Promise).Value[int]"(ptr %0)
%2 = add i64 %3, %1
call void @"github.com/goplus/llgo/x/async.(*Promise).Next[int]"(ptr %0)
br label %_llgo_3
_llgo_2: ; preds = %_llgo_3
ret i64 %3
_llgo_3: ; preds = %_llgo_1, %_llgo_0
%3 = phi i64 [ 0, %_llgo_0 ], [ %2, %_llgo_1 ]
%4 = call i1 @"github.com/goplus/llgo/x/async.(*Promise).Done[int]"(ptr %0)
br i1 %4, label %_llgo_2, label %_llgo_1
}
define ptr @async.WrapGenInts() presplitcoroutine {
entry:
%id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
%frame.size = call i64 @llvm.coro.size.i64()
%alloc.size = add i64 16, %frame.size
%promise = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 %alloc.size)
%need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
br i1 %need.dyn.alloc, label %alloc, label %_llgo_5
alloc: ; preds = %entry
%0 = getelementptr ptr, ptr %promise, i64 16
br label %_llgo_5
clean: ; preds = %_llgo_5
%1 = call ptr @llvm.coro.free(token %id, ptr %hdl)
br label %suspend
suspend: ; preds = %_llgo_5, %clean
%2 = call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
ret ptr %promise
trap: ; preds = %_llgo_5
call void @llvm.trap()
unreachable
_llgo_5: ; preds = %alloc, %entry
%frame = phi ptr [ null, %entry ], [ %0, %alloc ]
%hdl = call ptr @llvm.coro.begin(token %id, ptr %frame)
store ptr %hdl, ptr %promise, align 8
%3 = call ptr @async.GenInts()
%4 = call i8 @llvm.coro.suspend(token %id, i1 true)
switch i8 %4, label %suspend [
i8 0, label %trap
i8 1, label %clean
]
}
define void @async.init() {
_llgo_0:
%0 = load i1, ptr @"async.init$guard", align 1
br i1 %0, label %_llgo_2, label %_llgo_1
_llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"async.init$guard", align 1
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: read)
declare token @llvm.coro.id(i32, ptr readnone, ptr nocapture readonly, ptr)
; Function Attrs: nounwind memory(none)
declare i64 @llvm.coro.size.i64()
declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64)
; Function Attrs: nounwind
declare i1 @llvm.coro.alloc(token)
; Function Attrs: nounwind
declare ptr @llvm.coro.begin(token, ptr writeonly)
; Function Attrs: nounwind memory(argmem: read)
declare ptr @llvm.coro.free(token, ptr nocapture readonly)
; Function Attrs: nounwind
declare i1 @llvm.coro.end(ptr, i1, token)
; Function Attrs: cold noreturn nounwind memory(inaccessiblemem: write)
declare void @llvm.trap()
define void @"github.com/goplus/llgo/x/async.(*Promise).setValue[int]"(ptr %0, i64 %1) {
_llgo_0:
%2 = getelementptr inbounds %"github.com/goplus/llgo/x/async.Promise[int]", ptr %0, i32 0, i32 1
store i64 %1, ptr %2, align 4
ret void
}
; Function Attrs: nounwind
declare i8 @llvm.coro.suspend(token, i1)
define i1 @"github.com/goplus/llgo/x/async.(*Promise).Done[int]"(ptr %0) {
_llgo_0:
%1 = getelementptr inbounds %"github.com/goplus/llgo/x/async.Promise[int]", ptr %0, i32 0, i32 0
%2 = load ptr, ptr %1, align 8
%3 = call i1 @llvm.coro.done(ptr %2)
%4 = zext i1 %3 to i64
%5 = trunc i64 %4 to i8
%6 = icmp ne i8 %5, 0
ret i1 %6
}
define i64 @"github.com/goplus/llgo/x/async.(*Promise).Value[int]"(ptr %0) {
_llgo_0:
%1 = getelementptr inbounds %"github.com/goplus/llgo/x/async.Promise[int]", ptr %0, i32 0, i32 1
%2 = load i64, ptr %1, align 4
ret i64 %2
}
define void @"github.com/goplus/llgo/x/async.(*Promise).Next[int]"(ptr %0) {
_llgo_0:
%1 = getelementptr inbounds %"github.com/goplus/llgo/x/async.Promise[int]", ptr %0, i32 0, i32 0
%2 = load ptr, ptr %1, align 8
call void @llvm.coro.resume(ptr %2)
ret void
}
; Function Attrs: nounwind memory(argmem: readwrite)
declare i1 @llvm.coro.done(ptr nocapture readonly)
declare void @llvm.coro.resume(ptr)

View File

@@ -543,10 +543,12 @@ _llgo_0:
define void @"main.init#7"() { define void @"main.init#7"() {
_llgo_0: _llgo_0:
%0 = load ptr, ptr @"map[_llgo_int]_llgo_string", align 8 %0 = load ptr, ptr @_llgo_int, align 8
%1 = call ptr @"github.com/goplus/llgo/internal/runtime.MakeMap"(ptr %0, i64 0) %1 = load ptr, ptr @_llgo_string, align 8
%2 = icmp ne ptr %1, null %2 = load ptr, ptr @"map[_llgo_int]_llgo_string", align 8
call void @main.assert(i1 %2) %3 = call ptr @"github.com/goplus/llgo/internal/runtime.MakeMap"(ptr %2, i64 0)
%4 = icmp ne ptr %3, null
call void @main.assert(i1 %4)
call void @main.assert(i1 true) call void @main.assert(i1 true)
ret void ret void
} }

View File

@@ -7,6 +7,7 @@ func main() {
make4() make4()
make5() make5()
make6() make6()
make7()
} }
func make1() { func make1() {
@@ -113,3 +114,15 @@ func make6() {
println(k, v) println(k, v)
} }
} }
func make7() {
type N int
m := map[N]string{
1: "hello",
2: "world",
}
for k, v := range m {
println(k, v)
}
println(m[1])
}

File diff suppressed because it is too large Load Diff

View File

@@ -8,6 +8,7 @@ source_filename = "main"
@"main.init$guard" = global i1 false, align 1 @"main.init$guard" = global i1 false, align 1
@__llgo_argc = global i32 0, align 4 @__llgo_argc = global i32 0, align 4
@__llgo_argv = global ptr null, align 8 @__llgo_argv = global ptr null, align 8
@_llgo_int = linkonce global ptr null, align 8
@"map[_llgo_int]_llgo_int" = linkonce global ptr null, align 8 @"map[_llgo_int]_llgo_int" = linkonce global ptr null, align 8
@0 = private unnamed_addr constant [7 x i8] c"topbits", align 1 @0 = private unnamed_addr constant [7 x i8] c"topbits", align 1
@1 = private unnamed_addr constant [4 x i8] c"keys", align 1 @1 = private unnamed_addr constant [4 x i8] c"keys", align 1
@@ -36,24 +37,32 @@ _llgo_0:
store ptr %1, ptr @__llgo_argv, align 8 store ptr %1, ptr @__llgo_argv, align 8
call void @"github.com/goplus/llgo/internal/runtime.init"() call void @"github.com/goplus/llgo/internal/runtime.init"()
call void @main.init() call void @main.init()
%2 = load ptr, ptr @"map[_llgo_int]_llgo_int", align 8 %2 = load ptr, ptr @_llgo_int, align 8
%3 = call ptr @"github.com/goplus/llgo/internal/runtime.MakeMap"(ptr %2, i64 2) %3 = load ptr, ptr @_llgo_int, align 8
%4 = load ptr, ptr @"map[_llgo_int]_llgo_int", align 8 %4 = load ptr, ptr @"map[_llgo_int]_llgo_int", align 8
%5 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 8) %5 = call ptr @"github.com/goplus/llgo/internal/runtime.MakeMap"(ptr %4, i64 2)
store i64 23, ptr %5, align 4 %6 = load ptr, ptr @_llgo_int, align 8
%6 = call ptr @"github.com/goplus/llgo/internal/runtime.MapAssign"(ptr %4, ptr %3, ptr %5) %7 = load ptr, ptr @_llgo_int, align 8
store i64 100, ptr %6, align 4 %8 = load ptr, ptr @"map[_llgo_int]_llgo_int", align 8
%7 = load ptr, ptr @"map[_llgo_int]_llgo_int", align 8 %9 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 8)
%8 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 8) store i64 23, ptr %9, align 4
store i64 7, ptr %8, align 4 %10 = call ptr @"github.com/goplus/llgo/internal/runtime.MapAssign"(ptr %8, ptr %5, ptr %9)
%9 = call ptr @"github.com/goplus/llgo/internal/runtime.MapAssign"(ptr %7, ptr %3, ptr %8) store i64 100, ptr %10, align 4
store i64 29, ptr %9, align 4 %11 = load ptr, ptr @_llgo_int, align 8
%10 = load ptr, ptr @"map[_llgo_int]_llgo_int", align 8 %12 = load ptr, ptr @_llgo_int, align 8
%11 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 8) %13 = load ptr, ptr @"map[_llgo_int]_llgo_int", align 8
store i64 23, ptr %11, align 4 %14 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 8)
%12 = call ptr @"github.com/goplus/llgo/internal/runtime.MapAccess1"(ptr %10, ptr %3, ptr %11) store i64 7, ptr %14, align 4
%13 = load i64, ptr %12, align 4 %15 = call ptr @"github.com/goplus/llgo/internal/runtime.MapAssign"(ptr %13, ptr %5, ptr %14)
%14 = call i32 (ptr, ...) @printf(ptr @5, i64 %13) store i64 29, ptr %15, align 4
%16 = load ptr, ptr @_llgo_int, align 8
%17 = load ptr, ptr @_llgo_int, align 8
%18 = load ptr, ptr @"map[_llgo_int]_llgo_int", align 8
%19 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 8)
store i64 23, ptr %19, align 4
%20 = call ptr @"github.com/goplus/llgo/internal/runtime.MapAccess1"(ptr %18, ptr %5, ptr %19)
%21 = load i64, ptr %20, align 4
%22 = call i32 (ptr, ...) @printf(ptr @5, i64 %21)
ret i32 0 ret i32 0
} }
@@ -61,109 +70,119 @@ declare void @"github.com/goplus/llgo/internal/runtime.init"()
define void @"main.init$after"() { define void @"main.init$after"() {
_llgo_0: _llgo_0:
%0 = load ptr, ptr @"map[_llgo_int]_llgo_int", align 8 %0 = load ptr, ptr @_llgo_int, align 8
%1 = icmp eq ptr %0, null %1 = icmp eq ptr %0, null
br i1 %1, label %_llgo_1, label %_llgo_2 br i1 %1, label %_llgo_1, label %_llgo_2
_llgo_1: ; preds = %_llgo_0 _llgo_1: ; preds = %_llgo_0
%2 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 34) %2 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 34)
%3 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 34) store ptr %2, ptr @_llgo_int, align 8
%4 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %4, i32 0, i32 0
store ptr @0, ptr %5, align 8
%6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %4, i32 0, i32 1
store i64 7, ptr %6, align 4
%7 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %4, align 8
%8 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %8, i32 0, i32 0
store ptr null, ptr %9, align 8
%10 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %8, i32 0, i32 1
store i64 0, ptr %10, align 4
%11 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %8, align 8
%12 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 40)
%13 = call ptr @"github.com/goplus/llgo/internal/runtime.ArrayOf"(i64 8, ptr %12)
%14 = call %"github.com/goplus/llgo/internal/abi.StructField" @"github.com/goplus/llgo/internal/runtime.StructField"(%"github.com/goplus/llgo/internal/runtime.String" %7, ptr %13, i64 0, %"github.com/goplus/llgo/internal/runtime.String" %11, i1 false)
%15 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%16 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %15, i32 0, i32 0
store ptr @1, ptr %16, align 8
%17 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %15, i32 0, i32 1
store i64 4, ptr %17, align 4
%18 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %15, align 8
%19 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%20 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %19, i32 0, i32 0
store ptr null, ptr %20, align 8
%21 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %19, i32 0, i32 1
store i64 0, ptr %21, align 4
%22 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %19, align 8
%23 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 34)
%24 = call ptr @"github.com/goplus/llgo/internal/runtime.ArrayOf"(i64 8, ptr %23)
%25 = call %"github.com/goplus/llgo/internal/abi.StructField" @"github.com/goplus/llgo/internal/runtime.StructField"(%"github.com/goplus/llgo/internal/runtime.String" %18, ptr %24, i64 8, %"github.com/goplus/llgo/internal/runtime.String" %22, i1 false)
%26 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%27 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %26, i32 0, i32 0
store ptr @2, ptr %27, align 8
%28 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %26, i32 0, i32 1
store i64 5, ptr %28, align 4
%29 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %26, align 8
%30 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%31 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %30, i32 0, i32 0
store ptr null, ptr %31, align 8
%32 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %30, i32 0, i32 1
store i64 0, ptr %32, align 4
%33 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %30, align 8
%34 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 34)
%35 = call ptr @"github.com/goplus/llgo/internal/runtime.ArrayOf"(i64 8, ptr %34)
%36 = call %"github.com/goplus/llgo/internal/abi.StructField" @"github.com/goplus/llgo/internal/runtime.StructField"(%"github.com/goplus/llgo/internal/runtime.String" %29, ptr %35, i64 72, %"github.com/goplus/llgo/internal/runtime.String" %33, i1 false)
%37 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%38 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %37, i32 0, i32 0
store ptr @3, ptr %38, align 8
%39 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %37, i32 0, i32 1
store i64 8, ptr %39, align 4
%40 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %37, align 8
%41 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%42 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %41, i32 0, i32 0
store ptr null, ptr %42, align 8
%43 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %41, i32 0, i32 1
store i64 0, ptr %43, align 4
%44 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %41, align 8
%45 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 44)
%46 = call %"github.com/goplus/llgo/internal/abi.StructField" @"github.com/goplus/llgo/internal/runtime.StructField"(%"github.com/goplus/llgo/internal/runtime.String" %40, ptr %45, i64 136, %"github.com/goplus/llgo/internal/runtime.String" %44, i1 false)
%47 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%48 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %47, i32 0, i32 0
store ptr @4, ptr %48, align 8
%49 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %47, i32 0, i32 1
store i64 4, ptr %49, align 4
%50 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %47, align 8
%51 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 224)
%52 = getelementptr %"github.com/goplus/llgo/internal/abi.StructField", ptr %51, i64 0
store %"github.com/goplus/llgo/internal/abi.StructField" %14, ptr %52, align 8
%53 = getelementptr %"github.com/goplus/llgo/internal/abi.StructField", ptr %51, i64 1
store %"github.com/goplus/llgo/internal/abi.StructField" %25, ptr %53, align 8
%54 = getelementptr %"github.com/goplus/llgo/internal/abi.StructField", ptr %51, i64 2
store %"github.com/goplus/llgo/internal/abi.StructField" %36, ptr %54, align 8
%55 = getelementptr %"github.com/goplus/llgo/internal/abi.StructField", ptr %51, i64 3
store %"github.com/goplus/llgo/internal/abi.StructField" %46, ptr %55, align 8
%56 = alloca %"github.com/goplus/llgo/internal/runtime.Slice", align 8
%57 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %56, i32 0, i32 0
store ptr %51, ptr %57, align 8
%58 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %56, i32 0, i32 1
store i64 4, ptr %58, align 4
%59 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %56, i32 0, i32 2
store i64 4, ptr %59, align 4
%60 = load %"github.com/goplus/llgo/internal/runtime.Slice", ptr %56, align 8
%61 = call ptr @"github.com/goplus/llgo/internal/runtime.Struct"(%"github.com/goplus/llgo/internal/runtime.String" %50, i64 144, %"github.com/goplus/llgo/internal/runtime.Slice" %60)
%62 = call ptr @"github.com/goplus/llgo/internal/runtime.MapOf"(ptr %2, ptr %3, ptr %61, i64 4)
call void @"github.com/goplus/llgo/internal/runtime.SetDirectIface"(ptr %62)
store ptr %62, ptr @"map[_llgo_int]_llgo_int", align 8
br label %_llgo_2 br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0 _llgo_2: ; preds = %_llgo_1, %_llgo_0
%3 = load ptr, ptr @"map[_llgo_int]_llgo_int", align 8
%4 = icmp eq ptr %3, null
br i1 %4, label %_llgo_3, label %_llgo_4
_llgo_3: ; preds = %_llgo_2
%5 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 34)
%6 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 34)
%7 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%8 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %7, i32 0, i32 0
store ptr @0, ptr %8, align 8
%9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %7, i32 0, i32 1
store i64 7, ptr %9, align 4
%10 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %7, align 8
%11 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%12 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %11, i32 0, i32 0
store ptr null, ptr %12, align 8
%13 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %11, i32 0, i32 1
store i64 0, ptr %13, align 4
%14 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %11, align 8
%15 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 40)
%16 = call ptr @"github.com/goplus/llgo/internal/runtime.ArrayOf"(i64 8, ptr %15)
%17 = call %"github.com/goplus/llgo/internal/abi.StructField" @"github.com/goplus/llgo/internal/runtime.StructField"(%"github.com/goplus/llgo/internal/runtime.String" %10, ptr %16, i64 0, %"github.com/goplus/llgo/internal/runtime.String" %14, i1 false)
%18 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%19 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %18, i32 0, i32 0
store ptr @1, ptr %19, align 8
%20 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %18, i32 0, i32 1
store i64 4, ptr %20, align 4
%21 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %18, align 8
%22 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%23 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %22, i32 0, i32 0
store ptr null, ptr %23, align 8
%24 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %22, i32 0, i32 1
store i64 0, ptr %24, align 4
%25 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %22, align 8
%26 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 34)
%27 = call ptr @"github.com/goplus/llgo/internal/runtime.ArrayOf"(i64 8, ptr %26)
%28 = call %"github.com/goplus/llgo/internal/abi.StructField" @"github.com/goplus/llgo/internal/runtime.StructField"(%"github.com/goplus/llgo/internal/runtime.String" %21, ptr %27, i64 8, %"github.com/goplus/llgo/internal/runtime.String" %25, i1 false)
%29 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%30 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %29, i32 0, i32 0
store ptr @2, ptr %30, align 8
%31 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %29, i32 0, i32 1
store i64 5, ptr %31, align 4
%32 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %29, align 8
%33 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%34 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %33, i32 0, i32 0
store ptr null, ptr %34, align 8
%35 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %33, i32 0, i32 1
store i64 0, ptr %35, align 4
%36 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %33, align 8
%37 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 34)
%38 = call ptr @"github.com/goplus/llgo/internal/runtime.ArrayOf"(i64 8, ptr %37)
%39 = call %"github.com/goplus/llgo/internal/abi.StructField" @"github.com/goplus/llgo/internal/runtime.StructField"(%"github.com/goplus/llgo/internal/runtime.String" %32, ptr %38, i64 72, %"github.com/goplus/llgo/internal/runtime.String" %36, i1 false)
%40 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%41 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %40, i32 0, i32 0
store ptr @3, ptr %41, align 8
%42 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %40, i32 0, i32 1
store i64 8, ptr %42, align 4
%43 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %40, align 8
%44 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%45 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %44, i32 0, i32 0
store ptr null, ptr %45, align 8
%46 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %44, i32 0, i32 1
store i64 0, ptr %46, align 4
%47 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %44, align 8
%48 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 44)
%49 = call %"github.com/goplus/llgo/internal/abi.StructField" @"github.com/goplus/llgo/internal/runtime.StructField"(%"github.com/goplus/llgo/internal/runtime.String" %43, ptr %48, i64 136, %"github.com/goplus/llgo/internal/runtime.String" %47, i1 false)
%50 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%51 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %50, i32 0, i32 0
store ptr @4, ptr %51, align 8
%52 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %50, i32 0, i32 1
store i64 4, ptr %52, align 4
%53 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %50, align 8
%54 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 224)
%55 = getelementptr %"github.com/goplus/llgo/internal/abi.StructField", ptr %54, i64 0
store %"github.com/goplus/llgo/internal/abi.StructField" %17, ptr %55, align 8
%56 = getelementptr %"github.com/goplus/llgo/internal/abi.StructField", ptr %54, i64 1
store %"github.com/goplus/llgo/internal/abi.StructField" %28, ptr %56, align 8
%57 = getelementptr %"github.com/goplus/llgo/internal/abi.StructField", ptr %54, i64 2
store %"github.com/goplus/llgo/internal/abi.StructField" %39, ptr %57, align 8
%58 = getelementptr %"github.com/goplus/llgo/internal/abi.StructField", ptr %54, i64 3
store %"github.com/goplus/llgo/internal/abi.StructField" %49, ptr %58, align 8
%59 = alloca %"github.com/goplus/llgo/internal/runtime.Slice", align 8
%60 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %59, i32 0, i32 0
store ptr %54, ptr %60, align 8
%61 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %59, i32 0, i32 1
store i64 4, ptr %61, align 4
%62 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %59, i32 0, i32 2
store i64 4, ptr %62, align 4
%63 = load %"github.com/goplus/llgo/internal/runtime.Slice", ptr %59, align 8
%64 = call ptr @"github.com/goplus/llgo/internal/runtime.Struct"(%"github.com/goplus/llgo/internal/runtime.String" %53, i64 144, %"github.com/goplus/llgo/internal/runtime.Slice" %63)
%65 = call ptr @"github.com/goplus/llgo/internal/runtime.MapOf"(ptr %5, ptr %6, ptr %64, i64 4)
call void @"github.com/goplus/llgo/internal/runtime.SetDirectIface"(ptr %65)
store ptr %65, ptr @"map[_llgo_int]_llgo_int", align 8
br label %_llgo_4
_llgo_4: ; preds = %_llgo_3, %_llgo_2
ret void ret void
} }
declare ptr @"github.com/goplus/llgo/internal/runtime.MapOf"(ptr, ptr, ptr, i64)
declare ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64) declare ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64)
declare ptr @"github.com/goplus/llgo/internal/runtime.MapOf"(ptr, ptr, ptr, i64)
declare ptr @"github.com/goplus/llgo/internal/runtime.Struct"(%"github.com/goplus/llgo/internal/runtime.String", i64, %"github.com/goplus/llgo/internal/runtime.Slice") declare ptr @"github.com/goplus/llgo/internal/runtime.Struct"(%"github.com/goplus/llgo/internal/runtime.String", i64, %"github.com/goplus/llgo/internal/runtime.Slice")
declare %"github.com/goplus/llgo/internal/abi.StructField" @"github.com/goplus/llgo/internal/runtime.StructField"(%"github.com/goplus/llgo/internal/runtime.String", ptr, i64, %"github.com/goplus/llgo/internal/runtime.String", i1) declare %"github.com/goplus/llgo/internal/abi.StructField" @"github.com/goplus/llgo/internal/runtime.StructField"(%"github.com/goplus/llgo/internal/runtime.String", ptr, i64, %"github.com/goplus/llgo/internal/runtime.String", i1)

View File

@@ -1,119 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cl
import (
"go/constant"
"go/types"
"strings"
llssa "github.com/goplus/llgo/ssa"
"golang.org/x/tools/go/ssa"
)
// TODO(lijie): need more generics, shouldn't limit to async.Promise
func promiseType(ty types.Type) (types.Type, bool) {
// ty is a generic type, so we need to check the package path and type name
if ptrTy, ok := ty.(*types.Pointer); ok {
ty = ptrTy.Elem()
if ty, ok := ty.(*types.Named); ok {
if ty.Obj().Pkg() == nil {
return nil, false
}
if ty.Obj().Pkg().Path() == "github.com/goplus/llgo/x/async" && ty.Obj().Name() == "Promise" {
return ty, true
}
}
}
return nil, false
}
// check function return async.Promise[T]
// TODO(lijie): make it generic
func isAsyncFunc(sig *types.Signature) bool {
r := sig.Results()
if r.Len() != 1 {
return false
}
ty := r.At(0).Type()
_, ok := promiseType(ty)
return ok
}
func (p *context) coAwait(b llssa.Builder, args []ssa.Value) llssa.Expr {
if !isAsyncFunc(b.Func.RawType().(*types.Signature)) {
panic("coAwait(promise *T) T: invalid context")
}
if len(args) == 1 {
// promise := p.compileValue(b, args[0])
b.Unreachable()
// return b.CoroutineAwait(promise)
}
panic("coAwait(promise *T) T: invalid arguments")
}
func (p *context) coSuspend(b llssa.Builder, final llssa.Expr) {
b.CoSuspend(b.AsyncToken(), final, nil)
}
func (p *context) coDone(b llssa.Builder, args []ssa.Value) llssa.Expr {
if len(args) != 1 {
panic("coDone(promise *T): invalid arguments")
}
hdl := p.compileValue(b, args[0])
return b.CoDone(hdl)
}
func (p *context) coResume(b llssa.Builder, args []ssa.Value) {
if len(args) == 1 {
hdl := p.compileValue(b, args[0])
b.CoResume(hdl)
}
}
func (p *context) getSetValueFunc(fn *ssa.Function) llssa.Function {
typ := fn.Signature.Recv().Type()
mthds := p.goProg.MethodSets.MethodSet(typ)
for i := 0; i < mthds.Len(); i++ {
m := mthds.At(i)
if ssaMthd := p.goProg.MethodValue(m); ssaMthd != nil {
if ssaMthd.Name() == "setValue" || strings.HasPrefix(ssaMthd.Name(), "setValue[") {
setValueFn, _, _ := p.compileFunction(ssaMthd)
return setValueFn
}
}
}
panic("method setValue not found on type " + typ.String())
}
func (p *context) coReturn(b llssa.Builder, fn *ssa.Function, args []ssa.Value) {
setValueFn := p.getSetValueFunc(fn)
value := p.compileValue(b, args[1])
b.CoReturn(setValueFn, value)
}
func (p *context) coYield(b llssa.Builder, fn *ssa.Function, args []ssa.Value) {
setValueFn := p.getSetValueFunc(fn)
value := p.compileValue(b, args[1])
// TODO(lijie): find whether the co.Yield/co.Return is the last instruction
final := b.Const(constant.MakeBool(false), b.Prog.Bool())
b.CoYield(setValueFn, value, final)
}
func (p *context) coRun(b llssa.Builder, args []ssa.Value) {
panic("coRun(): not implemented")
}

View File

@@ -218,7 +218,6 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
log.Println("==> NewFunc", name, "type:", sig.Recv(), sig, "ftype:", ftype) log.Println("==> NewFunc", name, "type:", sig.Recv(), sig, "ftype:", ftype)
} }
} }
async := isAsyncFunc(f.Signature)
if fn == nil { if fn == nil {
if name == "main" { if name == "main" {
argc := types.NewParam(token.NoPos, pkgTypes, "", types.Typ[types.Int32]) argc := types.NewParam(token.NoPos, pkgTypes, "", types.Typ[types.Int32])
@@ -228,24 +227,13 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
results := types.NewTuple(ret) results := types.NewTuple(ret)
sig = types.NewSignatureType(nil, nil, nil, params, results, false) sig = types.NewSignatureType(nil, nil, nil, params, results, false)
} }
fn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), hasCtx, async) fn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), hasCtx)
} }
nBlkOff := 0
if nblk := len(f.Blocks); nblk > 0 { if nblk := len(f.Blocks); nblk > 0 {
var entryBlk, allocBlk, cleanBlk, suspdBlk, trapBlk, beginBlk llssa.BasicBlock
if async {
nBlkOff = 5
entryBlk = fn.MakeBlock("entry")
allocBlk = fn.MakeBlock("alloc")
cleanBlk = fn.MakeBlock("clean")
suspdBlk = fn.MakeBlock("suspend")
trapBlk = fn.MakeBlock("trap")
}
fn.MakeBlocks(nblk) // to set fn.HasBody() = true fn.MakeBlocks(nblk) // to set fn.HasBody() = true
beginBlk = fn.Block(nBlkOff)
if f.Recover != nil { // set recover block if f.Recover != nil { // set recover block
// TODO(lijie): fix this for async function because of the block offset increase fn.SetRecover(fn.Block(f.Recover.Index))
fn.SetRecover(fn.Block(f.Recover.Index + nBlkOff))
} }
p.inits = append(p.inits, func() { p.inits = append(p.inits, func() {
p.fn = fn p.fn = fn
@@ -261,10 +249,6 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
log.Println("==> FuncBody", name) log.Println("==> FuncBody", name)
} }
b := fn.NewBuilder() b := fn.NewBuilder()
b.SetBlockOffset(nBlkOff)
if async {
b.BeginAsync(fn, entryBlk, allocBlk, cleanBlk, suspdBlk, trapBlk, beginBlk)
}
p.bvals = make(map[ssa.Value]llssa.Expr) p.bvals = make(map[ssa.Value]llssa.Expr)
off := make([]int, len(f.Blocks)) off := make([]int, len(f.Blocks))
for i, block := range f.Blocks { for i, block := range f.Blocks {
@@ -300,7 +284,7 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, do
var pkg = p.pkg var pkg = p.pkg
var fn = p.fn var fn = p.fn
var instrs = block.Instrs[n:] var instrs = block.Instrs[n:]
var ret = fn.Block(block.Index + b.BlockOffset()) var ret = fn.Block(block.Index)
b.SetBlock(ret) b.SetBlock(ret)
if doModInit { if doModInit {
if pyModInit = p.pyMod != ""; pyModInit { if pyModInit = p.pyMod != ""; pyModInit {
@@ -338,7 +322,7 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, do
modPtr := pkg.PyNewModVar(modName, true).Expr modPtr := pkg.PyNewModVar(modName, true).Expr
mod := b.Load(modPtr) mod := b.Load(modPtr)
cond := b.BinOp(token.NEQ, mod, prog.Nil(mod.Type)) cond := b.BinOp(token.NEQ, mod, prog.Nil(mod.Type))
newBlk := fn.MakeBlock("") newBlk := fn.MakeBlock()
b.If(cond, jumpTo, newBlk) b.If(cond, jumpTo, newBlk)
b.SetBlockEx(newBlk, llssa.AtEnd, false) b.SetBlockEx(newBlk, llssa.AtEnd, false)
b.Store(modPtr, b.PyImportMod(modPath)) b.Store(modPtr, b.PyImportMod(modPath))
@@ -670,11 +654,7 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
results = make([]llssa.Expr, 1) results = make([]llssa.Expr, 1)
results[0] = p.prog.IntVal(0, p.prog.CInt()) results[0] = p.prog.IntVal(0, p.prog.CInt())
} }
if b.Async() {
b.EndAsync()
} else {
b.Return(results...) b.Return(results...)
}
case *ssa.If: case *ssa.If:
fn := p.fn fn := p.fn
cond := p.compileValue(b, v.Cond) cond := p.compileValue(b, v.Cond)

View File

@@ -53,7 +53,7 @@ func TestFromTestrt(t *testing.T) {
} }
func TestFromTestdata(t *testing.T) { func TestFromTestdata(t *testing.T) {
cltest.FromDir(t, "", "./_testdata", true) cltest.FromDir(t, "", "./_testdata", false)
} }
func TestFromTestpymath(t *testing.T) { func TestFromTestpymath(t *testing.T) {
@@ -124,114 +124,3 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
} }
`) `)
} }
func TestAsyncFunc(t *testing.T) {
testCompile(t, `package foo
import "github.com/goplus/llgo/x/async"
func GenInts() (co *async.Promise[int]) {
co.Yield(1)
co.Yield(2)
return
}
`, `; ModuleID = 'foo'
source_filename = "foo"
@"foo.init$guard" = global i1 false, align 1
define ptr @foo.GenInts() presplitcoroutine {
entry:
%id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
%frame.size = call i64 @llvm.coro.size.i64()
%alloc.size = add i64 16, %frame.size
%promise = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 %alloc.size)
%need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
br i1 %need.dyn.alloc, label %alloc, label %_llgo_5
alloc: ; preds = %entry
%0 = getelementptr ptr, ptr %promise, i64 16
br label %_llgo_5
clean: ; preds = %_llgo_7, %_llgo_6, %_llgo_5
%1 = call ptr @llvm.coro.free(token %id, ptr %hdl)
br label %suspend
suspend: ; preds = %_llgo_7, %_llgo_6, %_llgo_5, %clean
%2 = call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
ret ptr %promise
trap: ; preds = %_llgo_7
call void @llvm.trap()
unreachable
_llgo_5: ; preds = %alloc, %entry
%frame = phi ptr [ null, %entry ], [ %0, %alloc ]
%hdl = call ptr @llvm.coro.begin(token %id, ptr %frame)
store ptr %hdl, ptr %promise, align 8
call void @"github.com/goplus/llgo/x/async.(*Promise).setValue[int]"(ptr %promise, i64 1)
%3 = call i8 @llvm.coro.suspend(token %id, i1 false)
switch i8 %3, label %suspend [
i8 0, label %_llgo_6
i8 1, label %clean
]
_llgo_6: ; preds = %_llgo_5
call void @"github.com/goplus/llgo/x/async.(*Promise).setValue[int]"(ptr %promise, i64 2)
%4 = call i8 @llvm.coro.suspend(token %id, i1 false)
switch i8 %4, label %suspend [
i8 0, label %_llgo_7
i8 1, label %clean
]
_llgo_7: ; preds = %_llgo_6
%5 = call i8 @llvm.coro.suspend(token %id, i1 true)
switch i8 %5, label %suspend [
i8 0, label %trap
i8 1, label %clean
]
}
define void @foo.init() {
_llgo_0:
%0 = load i1, ptr @"foo.init$guard", align 1
br i1 %0, label %_llgo_2, label %_llgo_1
_llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"foo.init$guard", align 1
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: read)
declare token @llvm.coro.id(i32, ptr readnone, ptr nocapture readonly, ptr)
; Function Attrs: nounwind memory(none)
declare i64 @llvm.coro.size.i64()
declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64)
; Function Attrs: nounwind
declare i1 @llvm.coro.alloc(token)
; Function Attrs: nounwind
declare ptr @llvm.coro.begin(token, ptr writeonly)
; Function Attrs: nounwind memory(argmem: read)
declare ptr @llvm.coro.free(token, ptr nocapture readonly)
; Function Attrs: nounwind
declare i1 @llvm.coro.end(ptr, i1, token)
; Function Attrs: cold noreturn nounwind memory(inaccessiblemem: write)
declare void @llvm.trap()
declare void @"github.com/goplus/llgo/x/async.(*Promise).setValue[int]"(ptr, i64)
; Function Attrs: nounwind
declare i8 @llvm.coro.suspend(token, i1)
`)
}

View File

@@ -412,16 +412,7 @@ const (
llgoAtomicUMax = llgoAtomicOpBase + llssa.OpUMax llgoAtomicUMax = llgoAtomicOpBase + llssa.OpUMax
llgoAtomicUMin = llgoAtomicOpBase + llssa.OpUMin llgoAtomicUMin = llgoAtomicOpBase + llssa.OpUMin
llgoCoBase = llgoInstrBase + 0x30 llgoAtomicOpLast = llgoAtomicOpBase + int(llssa.OpUMin)
llgoCoAwait = llgoCoBase + 0
llgoCoSuspend = llgoCoBase + 1
llgoCoDone = llgoCoBase + 2
llgoCoResume = llgoCoBase + 3
llgoCoReturn = llgoCoBase + 4
llgoCoYield = llgoCoBase + 5
llgoCoRun = llgoCoBase + 6
llgoAtomicOpLast = llgoCoRun
) )
func (p *context) funcName(fn *ssa.Function, ignore bool) (*types.Package, string, int) { func (p *context) funcName(fn *ssa.Function, ignore bool) (*types.Package, string, int) {

View File

@@ -133,7 +133,7 @@ func (p *context) stringData(b llssa.Builder, args []ssa.Value) (ret llssa.Expr)
} }
// func funcAddr(fn any) unsafe.Pointer // func funcAddr(fn any) unsafe.Pointer
func (p *context) funcAddr(b llssa.Builder, args []ssa.Value) llssa.Expr { func (p *context) funcAddr(_ llssa.Builder, args []ssa.Value) llssa.Expr {
if len(args) == 1 { if len(args) == 1 {
if fn, ok := args[0].(*ssa.MakeInterface); ok { if fn, ok := args[0].(*ssa.MakeInterface); ok {
if fnDecl, ok := fn.X.(*ssa.Function); ok { if fnDecl, ok := fn.X.(*ssa.Function); ok {
@@ -237,14 +237,6 @@ var llgoInstrs = map[string]int{
"atomicMin": int(llgoAtomicMin), "atomicMin": int(llgoAtomicMin),
"atomicUMax": int(llgoAtomicUMax), "atomicUMax": int(llgoAtomicUMax),
"atomicUMin": int(llgoAtomicUMin), "atomicUMin": int(llgoAtomicUMin),
"coAwait": int(llgoCoAwait),
"coResume": int(llgoCoResume),
"coSuspend": int(llgoCoSuspend),
"coDone": int(llgoCoDone),
"coReturn": int(llgoCoReturn),
"coYield": int(llgoCoYield),
"coRun": int(llgoCoRun),
} }
// funcOf returns a function by name and set ftype = goFunc, cFunc, etc. // funcOf returns a function by name and set ftype = goFunc, cFunc, etc.
@@ -273,8 +265,7 @@ func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyObj
return nil, nil, ignoredFunc return nil, nil, ignoredFunc
} }
sig := fn.Signature sig := fn.Signature
async := isAsyncFunc(sig) aFn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false)
aFn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false, async)
} }
} }
return return
@@ -399,20 +390,6 @@ func (p *context) call(b llssa.Builder, act llssa.DoAction, call *ssa.CallCommon
ret = p.funcAddr(b, args) ret = p.funcAddr(b, args)
case llgoUnreachable: // func unreachable() case llgoUnreachable: // func unreachable()
b.Unreachable() b.Unreachable()
case llgoCoAwait:
ret = p.coAwait(b, args)
case llgoCoSuspend:
p.coSuspend(b, p.prog.BoolVal(false))
case llgoCoDone:
return p.coDone(b, args)
case llgoCoResume:
p.coResume(b, args)
case llgoCoReturn:
p.coReturn(b, cv, args)
case llgoCoYield:
p.coYield(b, cv, args)
case llgoCoRun:
p.coRun(b, args)
default: default:
if ftype >= llgoAtomicOpBase && ftype <= llgoAtomicOpLast { if ftype >= llgoAtomicOpBase && ftype <= llgoAtomicOpLast {
ret = p.atomic(b, llssa.AtomicOp(ftype-llgoAtomicOpBase), args) ret = p.atomic(b, llssa.AtomicOp(ftype-llgoAtomicOpBase), args)

View File

@@ -757,11 +757,13 @@ func findDylibDep(exe, lib string) string {
type none struct{} type none struct{}
var hasAltPkg = map[string]none{ var hasAltPkg = map[string]none{
"crypto/hmac": {},
"crypto/md5": {}, "crypto/md5": {},
"crypto/rand": {},
"crypto/sha1": {}, "crypto/sha1": {},
"crypto/sha256": {}, "crypto/sha256": {},
"crypto/sha512": {}, "crypto/sha512": {},
"crypto/rand": {}, "crypto/subtle": {},
"fmt": {}, "fmt": {},
"hash/crc32": {}, "hash/crc32": {},
"internal/abi": {}, "internal/abi": {},

View File

@@ -0,0 +1,72 @@
package hmac
// llgo:skipall
import (
"crypto/sha256"
"crypto/subtle"
"hash"
"unsafe"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/openssl"
)
type eface struct {
_type unsafe.Pointer
funcPtr *unsafe.Pointer
}
func funcOf(a any) unsafe.Pointer {
e := (*eface)(unsafe.Pointer(&a))
return *e.funcPtr
}
type digest openssl.HMAC_CTX
func (d *digest) Size() int { panic("todo: hmac.(*digest).Size") }
func (d *digest) BlockSize() int { panic("todo: hmac.(*digest).BlockSize") }
func (d *digest) Reset() {
(*openssl.HMAC_CTX)(d).Reset()
}
func (d *digest) Write(p []byte) (nn int, err error) {
(*openssl.HMAC_CTX)(d).UpdateBytes(p)
return len(p), nil
}
func (d *digest) Sum(in []byte) []byte {
const Size = openssl.EVP_MAX_MD_SIZE
var digestLen c.Uint
hash := (*[Size]byte)(c.Alloca(Size))
(*openssl.HMAC_CTX)(d).Final(&hash[0], &digestLen)
return append(in, hash[:digestLen]...)
}
// New returns a new HMAC hash using the given [hash.Hash] type and key.
// New functions like sha256.New from [crypto/sha256] can be used as h.
// h must return a new Hash every time it is called.
// Note that unlike other hash implementations in the standard library,
// the returned Hash does not implement [encoding.BinaryMarshaler]
// or [encoding.BinaryUnmarshaler].
func New(h func() hash.Hash, key []byte) hash.Hash {
var md *openssl.EVP_MD
switch funcOf(h) {
case c.Func(sha256.New):
md = openssl.EVP_sha256()
default:
panic("todo: hmac.New: unsupported hash function")
}
ctx := openssl.NewHMAC_CTX()
ctx.InitBytes(key, md)
return (*digest)(ctx)
}
// Equal compares two MACs for equality without leaking timing information.
func Equal(mac1, mac2 []byte) bool {
// We don't have to be constant time if the lengths of the MACs are
// different as that suggests that a completely different hash function
// was used.
return subtle.ConstantTimeCompare(mac1, mac2) == 1
}

View File

@@ -1,3 +1,19 @@
/*
* 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 sha1 package sha1
// llgo:skipall // llgo:skipall

View File

@@ -1,3 +1,19 @@
/*
* 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 sha256 package sha256
import ( import (

View File

@@ -1,3 +1,19 @@
/*
* 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 sha256 package sha256
// llgo:skipall // llgo:skipall

View File

@@ -1,3 +1,19 @@
/*
* 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 sha512 package sha512
import ( import (

View File

@@ -1,3 +1,19 @@
/*
* 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 sha512 package sha512
// llgo:skipall // llgo:skipall

View File

@@ -14,26 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package async package subtle
// llgo:skip XORBytes
import ( import (
"unsafe"
_ "unsafe" _ "unsafe"
"github.com/goplus/llgo/c"
) )
// llgo:link coDone llgo.coDone
func coDone(hdl unsafe.Pointer) c.Char {
panic("should not executed")
}
// llgo:link coResume llgo.coResume
func coResume(hdl unsafe.Pointer) {
panic("should not executed")
}
// llgo:link coReturn llgo.coReturn
func coReturn(hdl unsafe.Pointer) {
panic("should not executed")
}

View File

@@ -0,0 +1,220 @@
// Copyright 2018 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 fmtsort provides a general stable ordering mechanism
// for maps, on behalf of the fmt and text/template packages.
// It is not guaranteed to be efficient and works only for types
// that are valid map keys.
package fmtsort
// llgo:skipall
import (
"reflect"
"sort"
)
// Note: Throughout this package we avoid calling reflect.Value.Interface as
// it is not always legal to do so and it's easier to avoid the issue than to face it.
// SortedMap represents a map's keys and values. The keys and values are
// aligned in index order: Value[i] is the value in the map corresponding to Key[i].
type SortedMap struct {
Key []reflect.Value
Value []reflect.Value
}
func (o *SortedMap) Len() int { return len(o.Key) }
func (o *SortedMap) Less(i, j int) bool { return compare(o.Key[i], o.Key[j]) < 0 }
func (o *SortedMap) Swap(i, j int) {
o.Key[i], o.Key[j] = o.Key[j], o.Key[i]
o.Value[i], o.Value[j] = o.Value[j], o.Value[i]
}
// Sort accepts a map and returns a SortedMap that has the same keys and
// values but in a stable sorted order according to the keys, modulo issues
// raised by unorderable key values such as NaNs.
//
// The ordering rules are more general than with Go's < operator:
//
// - when applicable, nil compares low
// - ints, floats, and strings order by <
// - NaN compares less than non-NaN floats
// - bool compares false before true
// - complex compares real, then imag
// - pointers compare by machine address
// - channel values compare by machine address
// - structs compare each field in turn
// - arrays compare each element in turn.
// Otherwise identical arrays compare by length.
// - interface values compare first by reflect.Type describing the concrete type
// and then by concrete value as described in the previous rules.
func Sort(mapValue reflect.Value) *SortedMap {
if mapValue.Type().Kind() != reflect.Map {
return nil
}
// Note: this code is arranged to not panic even in the presence
// of a concurrent map update. The runtime is responsible for
// yelling loudly if that happens. See issue 33275.
n := mapValue.Len()
key := make([]reflect.Value, 0, n)
value := make([]reflect.Value, 0, n)
iter := mapValue.MapRange()
for iter.Next() {
key = append(key, iter.Key())
value = append(value, iter.Value())
}
sorted := &SortedMap{
Key: key,
Value: value,
}
sort.Stable(sorted)
return sorted
}
// compare compares two values of the same type. It returns -1, 0, 1
// according to whether a > b (1), a == b (0), or a < b (-1).
// If the types differ, it returns -1.
// See the comment on Sort for the comparison rules.
func compare(aVal, bVal reflect.Value) int {
aType, bType := aVal.Type(), bVal.Type()
if aType != bType {
return -1 // No good answer possible, but don't return 0: they're not equal.
}
switch aVal.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
a, b := aVal.Int(), bVal.Int()
switch {
case a < b:
return -1
case a > b:
return 1
default:
return 0
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
a, b := aVal.Uint(), bVal.Uint()
switch {
case a < b:
return -1
case a > b:
return 1
default:
return 0
}
case reflect.String:
a, b := aVal.String(), bVal.String()
switch {
case a < b:
return -1
case a > b:
return 1
default:
return 0
}
case reflect.Float32, reflect.Float64:
return floatCompare(aVal.Float(), bVal.Float())
case reflect.Complex64, reflect.Complex128:
a, b := aVal.Complex(), bVal.Complex()
if c := floatCompare(real(a), real(b)); c != 0 {
return c
}
return floatCompare(imag(a), imag(b))
case reflect.Bool:
a, b := aVal.Bool(), bVal.Bool()
switch {
case a == b:
return 0
case a:
return 1
default:
return -1
}
case reflect.Pointer, reflect.UnsafePointer:
a, b := aVal.Pointer(), bVal.Pointer()
switch {
case a < b:
return -1
case a > b:
return 1
default:
return 0
}
case reflect.Chan:
if c, ok := nilCompare(aVal, bVal); ok {
return c
}
ap, bp := aVal.Pointer(), bVal.Pointer()
switch {
case ap < bp:
return -1
case ap > bp:
return 1
default:
return 0
}
case reflect.Struct:
for i := 0; i < aVal.NumField(); i++ {
if c := compare(aVal.Field(i), bVal.Field(i)); c != 0 {
return c
}
}
return 0
case reflect.Array:
for i := 0; i < aVal.Len(); i++ {
if c := compare(aVal.Index(i), bVal.Index(i)); c != 0 {
return c
}
}
return 0
case reflect.Interface:
if c, ok := nilCompare(aVal, bVal); ok {
return c
}
c := compare(reflect.ValueOf(aVal.Elem().Type()), reflect.ValueOf(bVal.Elem().Type()))
if c != 0 {
return c
}
return compare(aVal.Elem(), bVal.Elem())
default:
// Certain types cannot appear as keys (maps, funcs, slices), but be explicit.
panic("bad type in compare: " + aType.String())
}
}
// nilCompare checks whether either value is nil. If not, the boolean is false.
// If either value is nil, the boolean is true and the integer is the comparison
// value. The comparison is defined to be 0 if both are nil, otherwise the one
// nil value compares low. Both arguments must represent a chan, func,
// interface, map, pointer, or slice.
func nilCompare(aVal, bVal reflect.Value) (int, bool) {
if aVal.IsNil() {
if bVal.IsNil() {
return 0, true
}
return -1, true
}
if bVal.IsNil() {
return 1, true
}
return 0, false
}
// floatCompare compares two floating-point values. NaNs compare low.
func floatCompare(a, b float64) int {
switch {
case isNaN(a):
return -1 // No good answer if b is a NaN so don't bother checking.
case isNaN(b):
return 1
case a < b:
return -1
case a > b:
return 1
}
return 0
}
func isNaN(a float64) bool {
return a != a
}

View File

@@ -414,6 +414,9 @@ func (b Builder) abiType(t types.Type) Expr {
b.loadType(t.Elem()) b.loadType(t.Elem())
case *types.Array: case *types.Array:
b.abiType(t.Elem()) b.abiType(t.Elem())
case *types.Map:
b.abiType(t.Key())
b.abiType(t.Elem())
} }
g := b.loadType(t) g := b.loadType(t)
return b.Load(g.Expr) return b.Load(g.Expr)

View File

@@ -50,7 +50,7 @@ func TestFromTestrt(t *testing.T) {
} }
func TestFromTestdata(t *testing.T) { func TestFromTestdata(t *testing.T) {
cltest.FromDir(t, "", "../cl/_testdata", true) cltest.FromDir(t, "", "../cl/_testdata", false)
} }
func TestMakeInterface(t *testing.T) { func TestMakeInterface(t *testing.T) {

View File

@@ -1,690 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ssa
import (
"fmt"
"go/constant"
"go/token"
"go/types"
)
// declare void @llvm.coro.destroy(ptr <handle>)
// declare void @llvm.coro.resume(ptr <handle>)
// declare i1 @llvm.coro.done(ptr <handle>)
// declare ptr @llvm.coro.promise(ptr <ptr>, i32 <alignment>, i1 <from>)
// declare i32 @llvm.coro.size.i32()
// declare i64 @llvm.coro.size.i64()
// declare i32 @llvm.coro.align.i32()
// declare i64 @llvm.coro.align.i64()
// declare ptr @llvm.coro.begin(token <id>, ptr <mem>)
// declare ptr @llvm.coro.free(token %id, ptr <frame>)
// declare i1 @llvm.coro.alloc(token <id>)
// declare ptr @llvm.coro.noop()
// declare ptr @llvm.coro.frame()
// declare token @llvm.coro.id(i32 <align>, ptr <promise>, ptr <coroaddr>, ptr <fnaddrs>)
// declare token @llvm.coro.id.async(i32 <context size>, i32 <align>, ptr <context arg>, ptr <async function pointer>)
// declare token @llvm.coro.id.retcon(i32 <size>, i32 <align>, ptr <buffer>, ptr <continuation prototype>, ptr <alloc>, ptr <dealloc>)
// declare token @llvm.coro.id.retcon.once(i32 <size>, i32 <align>, ptr <buffer>, ptr <prototype>, ptr <alloc>, ptr <dealloc>)
// declare i1 @llvm.coro.end(ptr <handle>, i1 <unwind>, token <result.token>)
// declare token @llvm.coro.end.results(...)
// declare i1 @llvm.coro.end.async(ptr <handle>, i1 <unwind>, ...)
// declare i8 @llvm.coro.suspend(token <save>, i1 <final>)
// declare token @llvm.coro.save(ptr <handle>)
// declare {ptr, ptr, ptr} @llvm.coro.suspend.async(ptr <resume function>, ptr <context projection function>, ... <function to call> ... <arguments to function>)
// declare ptr @llvm.coro.prepare.async(ptr <coroutine function>)
// declare i1 @llvm.coro.suspend.retcon(...)
// declare void @await_suspend_function(ptr %awaiter, ptr %hdl)
// declare void @llvm.coro.await.suspend.void(ptr <awaiter>, ptr <handle>, ptr <await_suspend_function>)
// declare i1 @llvm.coro.await.suspend.bool(ptr <awaiter>, ptr <handle>, ptr <await_suspend_function>)
// declare void @llvm.coro.await.suspend.handle(ptr <awaiter>, ptr <handle>, ptr <await_suspend_function>)
// -----------------------------------------------------------------------------
// declare void @llvm.coro.destroy(ptr <handle>)
func (p Program) tyCoDestroy() *types.Signature {
if p.coDestroyTy == nil {
i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
params := types.NewTuple(i8Ptr)
p.coDestroyTy = types.NewSignatureType(nil, nil, nil, params, nil, false)
}
return p.coDestroyTy
}
// declare void @llvm.coro.resume(ptr <handle>)
func (p Program) tyCoResume() *types.Signature {
if p.coResumeTy == nil {
i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
params := types.NewTuple(i8Ptr)
p.coResumeTy = types.NewSignatureType(nil, nil, nil, params, nil, false)
}
return p.coResumeTy
}
// declare i1 @llvm.coro.done(ptr <handle>)
func (p Program) tyCoDone() *types.Signature {
if p.coDoneTy == nil {
i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
params := types.NewTuple(i8Ptr)
results := types.NewTuple(types.NewParam(token.NoPos, nil, "", p.Bool().raw.Type))
p.coDoneTy = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.coDoneTy
}
// declare ptr @llvm.coro.promise(ptr <ptr>, i32 <alignment>, i1 <from>)
func (p Program) tyCoPromise() *types.Signature {
if p.coPromiseTy == nil {
i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
i32 := types.NewParam(token.NoPos, nil, "", p.Int32().raw.Type)
boolParam := types.NewParam(token.NoPos, nil, "", p.Bool().raw.Type)
params := types.NewTuple(i8Ptr, i32, boolParam)
results := types.NewTuple(i8Ptr)
p.coPromiseTy = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.coPromiseTy
}
// declare i32 @llvm.coro.size.i32()
func (p Program) tyCoSizeI32() *types.Signature {
if p.coSizeI32Ty == nil {
results := types.NewTuple(types.NewParam(token.NoPos, nil, "", p.Int32().raw.Type))
p.coSizeI32Ty = types.NewSignatureType(nil, nil, nil, nil, results, false)
}
return p.coSizeI32Ty
}
// declare i64 @llvm.coro.size.i64()
func (p Program) tyCoSizeI64() *types.Signature {
if p.coSizeI64Ty == nil {
results := types.NewTuple(types.NewParam(token.NoPos, nil, "", p.Int64().raw.Type))
p.coSizeI64Ty = types.NewSignatureType(nil, nil, nil, nil, results, false)
}
return p.coSizeI64Ty
}
// declare i32 @llvm.coro.align.i32()
func (p Program) tyCoAlignI32() *types.Signature {
if p.coAlignI32Ty == nil {
results := types.NewTuple(types.NewParam(token.NoPos, nil, "", p.Int32().raw.Type))
p.coAlignI32Ty = types.NewSignatureType(nil, nil, nil, nil, results, false)
}
return p.coAlignI32Ty
}
// declare i64 @llvm.coro.align.i64()
func (p Program) tyCoAlignI64() *types.Signature {
if p.coAlignI64Ty == nil {
results := types.NewTuple(types.NewParam(token.NoPos, nil, "", p.Int64().raw.Type))
p.coAlignI64Ty = types.NewSignatureType(nil, nil, nil, nil, results, false)
}
return p.coAlignI64Ty
}
// declare ptr @llvm.coro.begin(token <id>, ptr <mem>)
func (p Program) tyCoBegin() *types.Signature {
if p.coBeginTy == nil {
tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type)
i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
params := types.NewTuple(tokenParam, i8Ptr)
results := types.NewTuple(i8Ptr)
p.coBeginTy = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.coBeginTy
}
// declare ptr @llvm.coro.free(token %id, ptr <frame>)
func (p Program) tyCoFree() *types.Signature {
if p.coFreeTy == nil {
tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type)
i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
params := types.NewTuple(tokenParam, i8Ptr)
results := types.NewTuple(i8Ptr)
p.coFreeTy = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.coFreeTy
}
// declare i1 @llvm.coro.alloc(token <id>)
func (p Program) tyCoAlloc() *types.Signature {
if p.coAllocTy == nil {
tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type)
params := types.NewTuple(tokenParam)
boolParam := types.NewParam(token.NoPos, nil, "", p.Bool().raw.Type)
results := types.NewTuple(boolParam)
p.coAllocTy = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.coAllocTy
}
// declare ptr @llvm.coro.noop()
func (p Program) tyCoNoop() *types.Signature {
if p.coNoopTy == nil {
results := types.NewTuple(types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type))
p.coNoopTy = types.NewSignatureType(nil, nil, nil, nil, results, false)
}
return p.coNoopTy
}
// declare ptr @llvm.coro.frame()
func (p Program) tyCoFrame() *types.Signature {
if p.coFrameTy == nil {
results := types.NewTuple(types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type))
p.coFrameTy = types.NewSignatureType(nil, nil, nil, nil, results, false)
}
return p.coFrameTy
}
// declare token @llvm.coro.id(i32 <align>, ptr <promise>, ptr <coroaddr>, ptr <fnaddrs>)
func (p Program) tyCoID() *types.Signature {
if p.coIDTy == nil {
i32 := types.NewParam(token.NoPos, nil, "", p.Int32().raw.Type)
i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
params := types.NewTuple(i32, i8Ptr, i8Ptr, i8Ptr)
tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type)
results := types.NewTuple(tokenParam)
p.coIDTy = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.coIDTy
}
/*
// declare token @llvm.coro.id.async(i32 <context size>, i32 <align>, ptr <context arg>, ptr <async function pointer>)
func (p Program) tyCoIDAsync() *types.Signature {
if p.coIDAsyncTy == nil {
i32 := types.NewParam(token.NoPos, nil, "", p.Int32().raw.Type)
i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
params := types.NewTuple(i32, i32, i8Ptr, i8Ptr)
tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type)
results := types.NewTuple(tokenParam)
p.coIDAsyncTy = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.coIDAsyncTy
}
// declare token @llvm.coro.id.retcon(i32 <size>, i32 <align>, ptr <buffer>, ptr <continuation prototype>, ptr <alloc>, ptr <dealloc>)
func (p Program) tyCoIDRetcon() *types.Signature {
if p.coIDRetconTy == nil {
i32 := types.NewParam(token.NoPos, nil, "", p.Int32().raw.Type)
i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
params := types.NewTuple(i32, i32, i8Ptr, i8Ptr, i8Ptr, i8Ptr)
tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type)
results := types.NewTuple(tokenParam)
p.coIDRetconTy = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.coIDRetconTy
}
// declare token @llvm.coro.id.retcon.once(i32 <size>, i32 <align>, ptr <buffer>, ptr <prototype>, ptr <alloc>, ptr <dealloc>)
func (p Program) tyCoIDRetconOnce() *types.Signature {
if p.coIDRetconOnceTy == nil {
i32 := types.NewParam(token.NoPos, nil, "", p.Int32().raw.Type)
i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
params := types.NewTuple(i32, i32, i8Ptr, i8Ptr, i8Ptr, i8Ptr)
tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type)
results := types.NewTuple(tokenParam)
p.coIDRetconOnceTy = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.coIDRetconOnceTy
}
*/
// declare i1 @llvm.coro.end(ptr <handle>, i1 <unwind>, token <result.token>)
func (p Program) tyCoEnd() *types.Signature {
if p.coEndTy == nil {
i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
boolParam := types.NewParam(token.NoPos, nil, "", p.Bool().raw.Type)
tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type)
params := types.NewTuple(i8Ptr, boolParam, tokenParam)
results := types.NewTuple(boolParam)
p.coEndTy = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.coEndTy
}
/*
// TODO(lijie): varargs
// declare token @llvm.coro.end.results(...)
func (p Program) tyCoEndResults() *types.Signature {
panic("not implemented")
}
// TODO(lijie): varargs
// declare i1 @llvm.coro.end.async(ptr <handle>, i1 <unwind>, ...)
func (p Program) tyCoEndAsync() *types.Signature {
panic("not implemented")
}
*/
// declare i8 @llvm.coro.suspend(token <save>, i1 <final>)
func (p Program) tyCoSuspend() *types.Signature {
if p.coSuspendTy == nil {
tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type)
boolParam := types.NewParam(token.NoPos, nil, "", p.Bool().raw.Type)
params := types.NewTuple(tokenParam, boolParam)
paramByte := types.NewParam(token.NoPos, nil, "", p.Byte().raw.Type)
results := types.NewTuple(paramByte)
p.coSuspendTy = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.coSuspendTy
}
/*
// declare token @llvm.coro.save(ptr <handle>)
func (p Program) tyCoSave() *types.Signature {
if p.coSaveTy == nil {
i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
params := types.NewTuple(i8Ptr)
tokenParam := types.NewParam(token.NoPos, nil, "", p.Token().raw.Type)
results := types.NewTuple(tokenParam)
p.coSaveTy = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.coSaveTy
}
// TODO(lijie): varargs
// declare {ptr, ptr, ptr} @llvm.coro.suspend.async(ptr <resume function>, ptr <context projection function>, ... <function to call> ... <arguments to function>)
func (p Program) tyCoSuspendAsync() *types.Signature {
panic("not implemented")
}
// declare ptr @llvm.coro.prepare.async(ptr <coroutine function>)
func (p Program) tyCoPrepareAsync() *types.Signature {
if p.coPrepareAsyncTy == nil {
i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
params := types.NewTuple(i8Ptr)
results := types.NewTuple(i8Ptr)
p.coPrepareAsyncTy = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.coPrepareAsyncTy
}
// declare i1 @llvm.coro.suspend.retcon(...)
func (p Program) tyCoSuspendRetcon() *types.Signature {
panic("not implemented")
}
// declare void @await_suspend_function(ptr %awaiter, ptr %hdl)
func (p Program) tyCoAwaitSuspendFunction() *types.Signature {
if p.coAwaitSuspendFunctionTy == nil {
i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
params := types.NewTuple(i8Ptr, i8Ptr)
p.coAwaitSuspendFunctionTy = types.NewSignatureType(nil, nil, nil, params, nil, false)
}
return p.coAwaitSuspendFunctionTy
}
// declare void @llvm.coro.await.suspend.void(ptr <awaiter>, ptr <handle>, ptr <await_suspend_function>)
func (p Program) tyCoAwaitSuspendVoid() *types.Signature {
if p.coAwaitSuspendVoidTy == nil {
i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
params := types.NewTuple(i8Ptr, i8Ptr, i8Ptr)
p.coAwaitSuspendVoidTy = types.NewSignatureType(nil, nil, nil, params, nil, false)
}
return p.coAwaitSuspendVoidTy
}
// declare i1 @llvm.coro.await.suspend.bool(ptr <awaiter>, ptr <handle>, ptr <await_suspend_function>)
func (p Program) tyCoAwaitSuspendBool() *types.Signature {
if p.coAwaitSuspendBoolTy == nil {
i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
params := types.NewTuple(i8Ptr, i8Ptr, i8Ptr)
results := types.NewTuple(types.NewParam(token.NoPos, nil, "", p.Bool().raw.Type))
p.coAwaitSuspendBoolTy = types.NewSignatureType(nil, nil, nil, params, results, false)
}
return p.coAwaitSuspendBoolTy
}
// declare void @llvm.coro.await.suspend.handle(ptr <awaiter>, ptr <handle>, ptr <await_suspend_function>)
func (p Program) tyCoAwaitSuspendHandle() *types.Signature {
if p.coAwaitSuspendHandleTy == nil {
i8Ptr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
params := types.NewTuple(i8Ptr, i8Ptr, i8Ptr)
p.coAwaitSuspendHandleTy = types.NewSignatureType(nil, nil, nil, params, nil, false)
}
return p.coAwaitSuspendHandleTy
}
*/
// -----------------------------------------------------------------------------
func (b Builder) SetBlockOffset(offset int) {
b.blkOffset = offset
}
func (b Builder) BlockOffset() int {
return b.blkOffset
}
func (b Builder) Async() bool {
return b.async
}
func (b Builder) AsyncToken() Expr {
return b.asyncToken
}
func (b Builder) EndAsync() {
b.onReturn()
}
/*
pesudo code:
retPtr := malloc(sizeof(Promise))
id := @llvm.coro.id(0, null, null, null)
promiseSize := sizeof(Promise[T])
frameSize := @llvm.coro.size.i64()
allocSize := promiseSize + frameSize
promise := malloc(allocSize)
needAlloc := @llvm.coro.alloc(id)
; Allocate memory for return type and coroutine frame
frame := null
if needAlloc {
frame := malloc(frameSize)
}
hdl := @llvm.coro.begin(id, frame)
*retPtr = hdl
*/
func (b Builder) BeginAsync(fn Function, entryBlk, allocBlk, cleanBlk, suspdBlk, trapBlk, beginBlk BasicBlock) {
ty := fn.Type.RawType().(*types.Signature).Results().At(0).Type()
ptrTy, ok := ty.(*types.Pointer)
if !ok {
panic("async function must return a *async.Promise")
}
promiseTy := b.Prog.Type(ptrTy.Elem(), InGo)
b.async = true
b.SetBlock(entryBlk)
align := b.Const(constant.MakeInt64(0), b.Prog.CInt()).SetName("align")
null := b.Const(nil, b.Prog.CIntPtr())
id := b.CoID(align, null, null, null).SetName("id")
b.asyncToken = id
promiseSize := b.Const(constant.MakeUint64(b.Prog.SizeOf(promiseTy)), b.Prog.Int64()).SetName("alloc.size")
frameSize := b.CoSizeI64().SetName("frame.size")
allocSize := b.BinOp(token.ADD, promiseSize, frameSize).SetName("alloc.size")
promise := b.AllocZ(allocSize).SetName("promise")
b.promise = promise
promise.Type = b.Prog.Pointer(promiseTy)
needAlloc := b.CoAlloc(id).SetName("need.dyn.alloc")
b.If(needAlloc, allocBlk, beginBlk)
b.SetBlock(allocBlk)
frame := b.OffsetPtr(promise, promiseSize)
b.Jump(beginBlk)
b.SetBlock(beginBlk)
phi := b.Phi(b.Prog.VoidPtr())
phi.SetName("frame")
phi.AddIncoming(b, []BasicBlock{entryBlk, allocBlk}, func(i int, blk BasicBlock) Expr {
if i == 0 {
return null
}
return frame
})
hdl := b.CoBegin(id, phi.Expr)
hdl.SetName("hdl")
b.Store(promise, hdl)
b.SetBlock(cleanBlk)
b.CoFree(id, hdl)
b.Jump(suspdBlk)
b.SetBlock(suspdBlk)
b.CoEnd(hdl, b.Prog.BoolVal(false), b.Prog.TokenNone())
b.Return(promise)
b.SetBlock(trapBlk)
b.LLVMTrap()
b.Unreachable()
b.onSuspBlk = func(nextBlk BasicBlock) (BasicBlock, BasicBlock, BasicBlock) {
if nextBlk == nil {
nextBlk = trapBlk
}
return suspdBlk, nextBlk, cleanBlk
}
b.onReturn = func() {
b.CoSuspend(b.asyncToken, b.Prog.BoolVal(true), trapBlk)
}
}
// -----------------------------------------------------------------------------
// declare void @llvm.coro.destroy(ptr <handle>)
func (b Builder) CoDestroy(hdl Expr) {
fn := b.Pkg.cFunc("llvm.coro.destroy", b.Prog.tyCoDestroy())
b.Call(fn, hdl)
}
// declare void @llvm.coro.resume(ptr <handle>)
func (b Builder) CoResume(hdl Expr) {
fn := b.Pkg.cFunc("llvm.coro.resume", b.Prog.tyCoResume())
b.Call(fn, hdl)
}
// declare i1 @llvm.coro.done(ptr <handle>)
func (b Builder) coDone(hdl Expr) Expr {
fn := b.Pkg.cFunc("llvm.coro.done", b.Prog.tyCoDone())
return b.Call(fn, hdl)
}
// return c.Char
func (b Builder) CoDone(hdl Expr) Expr {
bvar := b.coDone(hdl)
// TODO(lijie): inefficient
// %6 = zext i1 %5 to i64
// %7 = trunc i64 %6 to i8
return b.valFromData(b.Prog.Byte(), bvar.impl)
}
// declare ptr @llvm.coro.promise(ptr <ptr>, i32 <alignment>, i1 <from>)
func (b Builder) CoPromise(ptr, align, from Expr) Expr {
fn := b.Pkg.cFunc("llvm.coro.promise", b.Prog.tyCoPromise())
return b.Call(fn, ptr, align, from)
}
// declare i32 @llvm.coro.size.i32()
func (b Builder) CoSizeI32() Expr {
fn := b.Pkg.cFunc("llvm.coro.size.i32", b.Prog.tyCoSizeI32())
return b.Call(fn)
}
// declare i64 @llvm.coro.size.i64()
func (b Builder) CoSizeI64() Expr {
fn := b.Pkg.cFunc("llvm.coro.size.i64", b.Prog.tyCoSizeI64())
return b.Call(fn)
}
// declare i32 @llvm.coro.align.i32()
func (b Builder) CoAlignI32() Expr {
fn := b.Pkg.cFunc("llvm.coro.align.i32", b.Prog.tyCoAlignI32())
return b.Call(fn)
}
// declare i64 @llvm.coro.align.i64()
func (b Builder) CoAlignI64() Expr {
fn := b.Pkg.cFunc("llvm.coro.align.i64", b.Prog.tyCoAlignI64())
return b.Call(fn)
}
// declare ptr @llvm.coro.begin(token <id>, ptr <mem>)
func (b Builder) CoBegin(id, mem Expr) Expr {
fn := b.Pkg.cFunc("llvm.coro.begin", b.Prog.tyCoBegin())
return b.Call(fn, id, mem)
}
// declare ptr @llvm.coro.free(token %id, ptr <frame>)
func (b Builder) CoFree(id, frame Expr) Expr {
fn := b.Pkg.cFunc("llvm.coro.free", b.Prog.tyCoFree())
return b.Call(fn, id, frame)
}
// declare i1 @llvm.coro.alloc(token <id>)
func (b Builder) CoAlloc(id Expr) Expr {
fn := b.Pkg.cFunc("llvm.coro.alloc", b.Prog.tyCoAlloc())
return b.Call(fn, id)
}
// declare ptr @llvm.coro.noop()
func (b Builder) CoNoop() Expr {
fn := b.Pkg.cFunc("llvm.coro.noop", b.Prog.tyCoNoop())
return b.Call(fn)
}
// declare ptr @llvm.coro.frame()
func (b Builder) CoFrame() Expr {
fn := b.Pkg.cFunc("llvm.coro.frame", b.Prog.tyCoFrame())
return b.Call(fn)
}
// declare token @llvm.coro.id(i32 <align>, ptr <promise>, ptr <coroaddr>, ptr <fnaddrs>)
func (b Builder) CoID(align Expr, promise, coroAddr, fnAddrs Expr) Expr {
if align.Type != b.Prog.Int32() {
panic("align must be i32")
}
fn := b.Pkg.cFunc("llvm.coro.id", b.Prog.tyCoID())
return b.Call(fn, align, promise, coroAddr, fnAddrs)
}
/*
// declare token @llvm.coro.id.async(i32 <context size>, i32 <align>, ptr <context arg>, ptr <async function pointer>)
func (b Builder) CoIDAsync(contextSize, align, contextArg, asyncFnPtr Expr) Expr {
if contextSize.Type != b.Prog.Int32() {
panic("contextSize must be i32")
}
if align.Type != b.Prog.Int32() {
panic("align must be i32")
}
fn := b.Pkg.cFunc("llvm.coro.id.async", b.Prog.tyCoIDAsync())
return b.Call(fn, contextSize, align, contextArg, asyncFnPtr)
}
// declare token @llvm.coro.id.retcon(i32 <size>, i32 <align>, ptr <buffer>, ptr <continuation prototype>, ptr <alloc>, ptr <dealloc>)
func (b Builder) CoIDRetcon(size, align, buffer, contProto, alloc, dealloc Expr) Expr {
fn := b.Pkg.cFunc("llvm.coro.id.retcon", b.Prog.tyCoIDRetcon())
return b.Call(fn, size, align, buffer, contProto, alloc, dealloc)
}
// declare token @llvm.coro.id.retcon.once(i32 <size>, i32 <align>, ptr <buffer>, ptr <prototype>, ptr <alloc>, ptr <dealloc>)
func (b Builder) CoIDRetconOnce(size, align, buffer, prototype, alloc, dealloc Expr) Expr {
fn := b.Pkg.cFunc("llvm.coro.id.retcon.once", b.Prog.tyCoIDRetconOnce())
return b.Call(fn, size, align, buffer, prototype, alloc, dealloc)
}
*/
// declare i1 @llvm.coro.end(ptr <handle>, i1 <unwind>, token <result.token>)
func (b Builder) CoEnd(hdl Expr, unwind Expr, resultToken Expr) Expr {
fn := b.Pkg.cFunc("llvm.coro.end", b.Prog.tyCoEnd())
return b.Call(fn, hdl, unwind, resultToken)
}
/*
// declare token @llvm.coro.end.results(...)
func (b Builder) CoEndResults(args []Expr) Expr {
fn := b.Pkg.cFunc("llvm.coro.end.results", b.Prog.tyCoEndResults())
return b.Call(fn, args...)
}
// declare i1 @llvm.coro.end.async(ptr <handle>, i1 <unwind>, ...)
func (b Builder) CoEndAsync(handle, unwind Expr, args ...Expr) Expr {
fn := b.Pkg.cFunc("llvm.coro.end.async", b.Prog.tyCoEndAsync())
vargs := append([]Expr{handle, unwind}, args...)
return b.Call(fn, vargs...)
}
*/
// declare i8 @llvm.coro.suspend(token <save>, i1 <final>)
func (b Builder) coSuspend(save, final Expr) Expr {
fn := b.Pkg.cFunc("llvm.coro.suspend", b.Prog.tyCoSuspend())
return b.Call(fn, save, final)
}
func (b Builder) CoSuspend(save, final Expr, nextBlk BasicBlock) {
if !b.async {
panic(fmt.Errorf("suspend %v not in async block", b.Func.Name()))
}
if nextBlk == nil {
b.Func.MakeBlock("")
nextBlk = b.Func.Block(b.blk.idx + 1)
}
ret := b.coSuspend(save, final)
susp, next, clean := b.onSuspBlk(nextBlk)
swt := b.Switch(ret, susp)
swt.Case(b.Const(constant.MakeInt64(0), b.Prog.Byte()), next)
swt.Case(b.Const(constant.MakeInt64(1), b.Prog.Byte()), clean)
swt.End(b)
b.SetBlock(nextBlk)
}
func (b Builder) CoReturn(setValueFn Function, value Expr) {
if !b.async {
panic(fmt.Errorf("return %v not in async block", b.Func.Name()))
}
b.Call(setValueFn.Expr, b.promise, value)
_, _, cleanBlk := b.onSuspBlk(nil)
b.Jump(cleanBlk)
}
func (b Builder) CoYield(setValueFn Function, value Expr, final Expr) {
if !b.async {
panic(fmt.Errorf("yield %v not in async block", b.Func.Name()))
}
b.Call(setValueFn.Expr, b.promise, value)
b.CoSuspend(b.AsyncToken(), final, nil)
}
/*
// declare token @llvm.coro.save(ptr <handle>)
func (b Builder) CoSave(hdl Expr) Expr {
fn := b.Pkg.cFunc("llvm.coro.save", b.Prog.tyCoSave())
return b.Call(fn, hdl)
}
// declare ptr @llvm.coro.prepare.async(ptr <coroutine function>)
func (b Builder) CoPrepareAsync(f Expr) Expr {
fn := b.Pkg.cFunc("llvm.coro.prepare.async", b.Prog.tyCoPrepareAsync())
return b.Call(fn, f)
}
// declare i1 @llvm.coro.suspend.retcon(...)
func (b Builder) CoSuspendRetcon(args []Expr) Expr {
fn := b.Pkg.cFunc("llvm.coro.suspend.retcon", b.Prog.tyCoSuspendRetcon())
return b.Call(fn, args...)
}
// declare void @llvm.coro.await.suspend.void(ptr <awaiter>, ptr <handle>, ptr <await_suspend_function>)
func (b Builder) CoAwaitSuspendVoid(awaiter, handle, f Expr) {
fn := b.Pkg.cFunc("llvm.coro.await.suspend.void", b.Prog.tyCoAwaitSuspendVoid())
b.Call(fn, awaiter, handle, f)
}
// declare i1 @llvm.coro.await.suspend.bool(ptr <awaiter>, ptr <handle>, ptr <await_suspend_function>)
func (b Builder) CoAwaitSuspendBool(awaiter, handle, f Expr) Expr {
fn := b.Pkg.cFunc("llvm.coro.await.suspend.bool", b.Prog.tyCoAwaitSuspendBool())
return b.Call(fn, awaiter, handle, f)
}
// declare void @llvm.coro.await.suspend.handle(ptr <awaiter>, ptr <handle>, ptr <await_suspend_function>)
func (b Builder) CoAwaitSuspendHandle(awaiter, handle, f Expr) {
fn := b.Pkg.cFunc("llvm.coro.await.suspend.handle", b.Prog.tyCoAwaitSuspendHandle())
b.Call(fn, awaiter, handle, f)
}
*/

View File

@@ -180,11 +180,11 @@ type Function = *aFunction
// NewFunc creates a new function. // NewFunc creates a new function.
func (p Package) NewFunc(name string, sig *types.Signature, bg Background) Function { func (p Package) NewFunc(name string, sig *types.Signature, bg Background) Function {
return p.NewFuncEx(name, sig, bg, false, false) return p.NewFuncEx(name, sig, bg, false)
} }
// NewFuncEx creates a new function. // NewFuncEx creates a new function.
func (p Package) NewFuncEx(name string, sig *types.Signature, bg Background, hasFreeVars, async bool) Function { func (p Package) NewFuncEx(name string, sig *types.Signature, bg Background, hasFreeVars bool) Function {
if v, ok := p.fns[name]; ok { if v, ok := p.fns[name]; ok {
return v return v
} }
@@ -193,9 +193,6 @@ func (p Package) NewFuncEx(name string, sig *types.Signature, bg Background, has
log.Println("NewFunc", name, t.raw.Type, "hasFreeVars:", hasFreeVars) log.Println("NewFunc", name, t.raw.Type, "hasFreeVars:", hasFreeVars)
} }
fn := llvm.AddFunction(p.mod, name, t.ll) fn := llvm.AddFunction(p.mod, name, t.ll)
if async {
fn.AddFunctionAttr(p.Prog.ctx.CreateStringAttribute("presplitcoroutine", ""))
}
ret := newFunction(fn, t, p, p.Prog, hasFreeVars) ret := newFunction(fn, t, p, p.Prog, hasFreeVars)
p.fns[name] = ret p.fns[name] = ret
return ret return ret
@@ -271,7 +268,7 @@ func (p Function) NewBuilder() Builder {
b := prog.ctx.NewBuilder() b := prog.ctx.NewBuilder()
// TODO(xsw): Finalize may cause panic, so comment it. // TODO(xsw): Finalize may cause panic, so comment it.
// b.Finalize() // b.Finalize()
return &aBuilder{impl: b, blk: nil, Func: p, Pkg: p.Pkg, Prog: prog} return &aBuilder{b, nil, p, p.Pkg, prog}
} }
// HasBody reports whether the function has a body. // HasBody reports whether the function has a body.
@@ -296,15 +293,13 @@ func (p Function) MakeBlocks(nblk int) []BasicBlock {
p.blks = make([]BasicBlock, 0, nblk) p.blks = make([]BasicBlock, 0, nblk)
} }
for i := 0; i < nblk; i++ { for i := 0; i < nblk; i++ {
p.addBlock(n+i, "") p.addBlock(n + i)
} }
return p.blks[n:] return p.blks[n:]
} }
func (p Function) addBlock(idx int, label string) BasicBlock { func (p Function) addBlock(idx int) BasicBlock {
if label == "" { label := "_llgo_" + strconv.Itoa(idx)
label = "_llgo_" + strconv.Itoa(idx)
}
blk := llvm.AddBasicBlock(p.impl, label) blk := llvm.AddBasicBlock(p.impl, label)
ret := &aBasicBlock{blk, blk, p, idx} ret := &aBasicBlock{blk, blk, p, idx}
p.blks = append(p.blks, ret) p.blks = append(p.blks, ret)
@@ -312,8 +307,8 @@ func (p Function) addBlock(idx int, label string) BasicBlock {
} }
// MakeBlock creates a new basic block for the function. // MakeBlock creates a new basic block for the function.
func (p Function) MakeBlock(label string) BasicBlock { func (p Function) MakeBlock() BasicBlock {
return p.addBlock(len(p.blks), label) return p.addBlock(len(p.blks))
} }
// Block returns the ith basic block of the function. // Block returns the ith basic block of the function.

View File

@@ -55,13 +55,6 @@ func (p Program) tySiglongjmp() *types.Signature {
return p.sigljmpTy return p.sigljmpTy
} }
func (p Program) tyLLVMTrap() *types.Signature {
if p.llvmTrapTy == nil {
p.llvmTrapTy = types.NewSignatureType(nil, nil, nil, nil, nil, false)
}
return p.llvmTrapTy
}
func (b Builder) AllocaSigjmpBuf() Expr { func (b Builder) AllocaSigjmpBuf() Expr {
prog := b.Prog prog := b.Prog
n := unsafe.Sizeof(sigjmpbuf{}) n := unsafe.Sizeof(sigjmpbuf{})
@@ -84,11 +77,6 @@ func (b Builder) Siglongjmp(jb, retval Expr) {
// b.Unreachable() // b.Unreachable()
} }
func (b Builder) LLVMTrap() {
fn := b.Pkg.cFunc("llvm.trap", b.Prog.tyLLVMTrap())
b.Call(fn)
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
const ( const (
@@ -178,7 +166,7 @@ func (b Builder) getDefer(kind DoAction) *aDefer {
czero := prog.IntVal(0, prog.CInt()) czero := prog.IntVal(0, prog.CInt())
retval := b.Sigsetjmp(jb, czero) retval := b.Sigsetjmp(jb, czero)
if kind != DeferAlways { if kind != DeferAlways {
panicBlk = self.MakeBlock("") panicBlk = self.MakeBlock()
} else { } else {
blks = self.MakeBlocks(2) blks = self.MakeBlocks(2)
next, panicBlk = blks[0], blks[1] next, panicBlk = blks[0], blks[1]
@@ -252,7 +240,7 @@ func (b Builder) Defer(kind DoAction, fn Expr, args ...Expr) {
// RunDefers emits instructions to run deferred instructions. // RunDefers emits instructions to run deferred instructions.
func (b Builder) RunDefers() { func (b Builder) RunDefers() {
self := b.getDefer(DeferInCond) self := b.getDefer(DeferInCond)
blk := b.Func.MakeBlock("") blk := b.Func.MakeBlock()
self.rundsNext = append(self.rundsNext, blk) self.rundsNext = append(self.rundsNext, blk)
b.Store(self.rundPtr, blk.Addr()) b.Store(self.rundPtr, blk.Addr())

View File

@@ -59,11 +59,6 @@ func (v Expr) SetOrdering(ordering AtomicOrdering) Expr {
return v return v
} }
func (v Expr) SetName(name string) Expr {
v.impl.SetName(name)
return v
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
type builtinTy struct { type builtinTy struct {

View File

@@ -232,13 +232,6 @@ func (b Builder) ArrayAlloca(telem Type, n Expr) (ret Expr) {
return return
} }
func (b Builder) OffsetPtr(ptr, offset Expr) Expr {
if debugInstr {
log.Printf("OffsetPtr %v, %v\n", ptr.impl, offset.impl)
}
return Expr{llvm.CreateGEP(b.impl, ptr.Type.ll, ptr.impl, []llvm.Value{offset.impl}), ptr.Type}
}
/* TODO(xsw): /* TODO(xsw):
// ArrayAlloc allocates zero initialized space for an array of n elements of type telem. // ArrayAlloc allocates zero initialized space for an array of n elements of type telem.
func (b Builder) ArrayAlloc(telem Type, n Expr) (ret Expr) { func (b Builder) ArrayAlloc(telem Type, n Expr) (ret Expr) {

View File

@@ -19,10 +19,8 @@ package ssa
import ( import (
"go/token" "go/token"
"go/types" "go/types"
"regexp"
"runtime" "runtime"
"strconv" "strconv"
"strings"
"unsafe" "unsafe"
"github.com/goplus/llgo/ssa/abi" "github.com/goplus/llgo/ssa/abi"
@@ -138,8 +136,6 @@ type aProgram struct {
rtMapTy llvm.Type rtMapTy llvm.Type
rtChanTy llvm.Type rtChanTy llvm.Type
tokenType llvm.Type
anyTy Type anyTy Type
voidTy Type voidTy Type
voidPtr Type voidPtr Type
@@ -170,8 +166,6 @@ type aProgram struct {
deferTy Type deferTy Type
deferPtr Type deferPtr Type
tokenTy Type
pyImpTy *types.Signature pyImpTy *types.Signature
pyNewList *types.Signature pyNewList *types.Signature
pyListSetI *types.Signature pyListSetI *types.Signature
@@ -195,41 +189,6 @@ type aProgram struct {
sigsetjmpTy *types.Signature sigsetjmpTy *types.Signature
sigljmpTy *types.Signature sigljmpTy *types.Signature
llvmTrapTy *types.Signature
// coroutine manipulation intrinsics (ordered by LLVM coroutine doc)
coDestroyTy *types.Signature
coResumeTy *types.Signature
coDoneTy *types.Signature
coPromiseTy *types.Signature
// coroutine structure intrinsics (ordered by LLVM coroutine doc)
coSizeI32Ty *types.Signature
coSizeI64Ty *types.Signature
coAlignI32Ty *types.Signature
coAlignI64Ty *types.Signature
coBeginTy *types.Signature
coFreeTy *types.Signature
coAllocTy *types.Signature
coNoopTy *types.Signature
coFrameTy *types.Signature
coIDTy *types.Signature
// coIDAsyncTy *types.Signature
// coIDRetconTy *types.Signature
// coIDRetconOnceTy *types.Signature
coEndTy *types.Signature
// coEndResultsTy *types.Signature
// coEndAsyncTy *types.Signature
coSuspendTy *types.Signature
// coSaveTy *types.Signature
// coSuspendAsyncTy *types.Signature
// coPrepareAsyncTy *types.Signature
// coSuspendRetconTy *types.Signature
// coAwaitSuspendFunctionTy *types.Signature
// coAwaitSuspendVoidTy *types.Signature
// coAwaitSuspendBoolTy *types.Signature
// coAwaitSuspendHandleTy *types.Signature
paramObjPtr_ *types.Var paramObjPtr_ *types.Var
ptrSize int ptrSize int
@@ -482,18 +441,6 @@ func (p Program) Any() Type {
return p.anyTy return p.anyTy
} }
func (p Program) Token() Type {
if p.tokenTy == nil {
p.tokenTy = &aType{p.tyToken(), rawType{types.Typ[types.Invalid]}, vkInvalid}
}
return p.tokenTy
}
func (p Program) TokenNone() Expr {
impl := llvm.ConstNull(p.Token().ll)
return Expr{impl: impl, Type: p.Token()}
}
/* /*
// Eface returns the empty interface type. // Eface returns the empty interface type.
// It is equivalent to Any. // It is equivalent to Any.
@@ -702,41 +649,9 @@ func (p Package) Path() string {
return p.abi.Pkg return p.abi.Pkg
} }
// Find presplitcoroutine attribute and replace attribute tag with it
// e.g. attributes #0 = { noinline nounwind readnone "presplitcoroutine" }
// replace #0 with presplitcoroutine
// and also remove all other attributes
func removeLLVMAttributes(ll string) string {
attrRe := regexp.MustCompile(`^attributes (#\d+) = {[^}]*}$`)
attrRe2 := regexp.MustCompile(`(\) #\d+ {|\) #\d+)$`)
lines := strings.Split(ll, "\n")
newLines := make([]string, 0, len(lines))
presplitcoroutine := ""
for _, line := range lines {
if m := attrRe.FindStringSubmatch(line); m != nil {
if strings.Contains(line, "\"presplitcoroutine\"") {
presplitcoroutine = " " + m[1] + " "
}
} else {
newLines = append(newLines, line)
}
}
for i, line := range newLines {
if presplitcoroutine != "" {
line = strings.Replace(line, presplitcoroutine, " presplitcoroutine ", 1)
}
line = attrRe2.ReplaceAllString(line, ")")
newLines[i] = line
}
return strings.Join(newLines, "\n")
}
// String returns a string representation of the package. // String returns a string representation of the package.
func (p Package) String() string { func (p Package) String() string {
// TODO(lijie): workaround for compiling errors of LLVM attributes return p.mod.String()
return removeLLVMAttributes(p.mod.String())
} }
// SetPatch sets a patch function. // SetPatch sets a patch function.

View File

@@ -469,47 +469,6 @@ _llgo_0:
`) `)
} }
func TestSwitch(t *testing.T) {
prog := NewProgram(nil)
pkg := prog.NewPackage("bar", "foo/bar")
params := types.NewTuple(types.NewVar(0, nil, "a", types.Typ[types.Int]))
rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int]))
sig := types.NewSignatureType(nil, nil, nil, params, rets, false)
fn := pkg.NewFunc("fn", sig, InGo)
b := fn.MakeBody(4)
cond := fn.Param(0)
case1 := fn.Block(1)
case2 := fn.Block(2)
defb := fn.Block(3)
swc := b.Switch(cond, defb)
swc.Case(prog.Val(1), case1)
swc.Case(prog.Val(2), case2)
swc.End(b)
b.SetBlock(case1).Return(prog.Val(3))
b.SetBlock(case2).Return(prog.Val(4))
b.SetBlock(defb).Return(prog.Val(5))
assertPkg(t, pkg, `; ModuleID = 'foo/bar'
source_filename = "foo/bar"
define i64 @fn(i64 %0) {
_llgo_0:
switch i64 %0, label %_llgo_3 [
i64 1, label %_llgo_1
i64 2, label %_llgo_2
]
_llgo_1: ; preds = %_llgo_0
ret i64 3
_llgo_2: ; preds = %_llgo_0
ret i64 4
_llgo_3: ; preds = %_llgo_0
ret i64 5
}
`)
}
func TestUnOp(t *testing.T) { func TestUnOp(t *testing.T) {
prog := NewProgram(nil) prog := NewProgram(nil)
pkg := prog.NewPackage("bar", "foo/bar") pkg := prog.NewPackage("bar", "foo/bar")
@@ -593,194 +552,3 @@ _llgo_0:
} }
`) `)
} }
func TestPointerOffset(t *testing.T) {
prog := NewProgram(nil)
pkg := prog.NewPackage("bar", "foo/bar")
params := types.NewTuple(
types.NewVar(0, nil, "p", types.NewPointer(types.Typ[types.Int])),
types.NewVar(0, nil, "offset", types.Typ[types.Int]),
)
rets := types.NewTuple(types.NewVar(0, nil, "", types.NewPointer(types.Typ[types.Int])))
sig := types.NewSignatureType(nil, nil, nil, params, rets, false)
fn := pkg.NewFunc("fn", sig, InGo)
b := fn.MakeBody(1)
ptr := fn.Param(0)
offset := fn.Param(1)
result := b.OffsetPtr(ptr, offset)
b.Return(result)
assertPkg(t, pkg, `; ModuleID = 'foo/bar'
source_filename = "foo/bar"
define ptr @fn(ptr %0, i64 %1) {
_llgo_0:
%2 = getelementptr ptr, ptr %0, i64 %1
ret ptr %2
}
`)
}
func TestLLVMTrap(t *testing.T) {
prog := NewProgram(nil)
pkg := prog.NewPackage("bar", "foo/bar")
b := pkg.NewFunc("fn", NoArgsNoRet, InGo).MakeBody(1)
b.LLVMTrap()
b.Unreachable()
assertPkg(t, pkg, `; ModuleID = 'foo/bar'
source_filename = "foo/bar"
define void @fn() {
_llgo_0:
call void @llvm.trap()
unreachable
}
; Function Attrs: cold noreturn nounwind memory(inaccessiblemem: write)
declare void @llvm.trap()
`)
}
func TestCoroFuncs(t *testing.T) {
prog := NewProgram(nil)
pkg := prog.NewPackage("bar", "foo/bar")
fn := pkg.NewFunc("fn", NoArgsNoRet, InGo)
entryBlk := fn.MakeBlock("entry")
suspdBlk := fn.MakeBlock("suspend")
cleanBlk := fn.MakeBlock("clean")
b := fn.NewBuilder()
b.async = true
b.SetBlock(entryBlk)
align := b.Const(constant.MakeInt64(0), prog.Int32())
align8 := b.Const(constant.MakeInt64(8), prog.Int32())
null := b.Const(nil, b.Prog.CIntPtr())
b.promise = null
id := b.CoID(align, null, null, null)
bf := b.Const(constant.MakeBool(false), prog.Bool())
b.CoSizeI32()
size := b.CoSizeI64()
b.CoAlignI32()
b.CoAlignI64()
b.CoAlloc(id)
frame := b.Alloca(size)
hdl := b.CoBegin(id, frame)
b.SetBlock(cleanBlk)
b.CoFree(id, frame)
b.Jump(suspdBlk)
b.SetBlock(suspdBlk)
b.CoEnd(hdl, bf, prog.TokenNone())
// b.Return(b.promise)
b.SetBlock(entryBlk)
b.CoResume(hdl)
b.CoDone(hdl)
b.CoDestroy(hdl)
b.CoPromise(null, align8, bf)
b.CoNoop()
b.CoFrame()
setArgs := types.NewTuple(types.NewVar(0, nil, "value", types.Typ[types.Int]))
setSig := types.NewSignatureType(nil, nil, nil, setArgs, nil, false)
setFn := pkg.NewFunc("setValue", setSig, InGo)
one := b.Const(constant.MakeInt64(1), prog.Int())
b.onSuspBlk = func(next BasicBlock) (BasicBlock, BasicBlock, BasicBlock) {
return suspdBlk, next, cleanBlk
}
b.CoYield(setFn, one, bf)
b.CoReturn(setFn, one)
assertPkg(t, pkg, `; ModuleID = 'foo/bar'
source_filename = "foo/bar"
define void @fn() {
entry:
%0 = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
%1 = call i32 @llvm.coro.size.i32()
%2 = call i64 @llvm.coro.size.i64()
%3 = call i32 @llvm.coro.align.i32()
%4 = call i64 @llvm.coro.align.i64()
%5 = call i1 @llvm.coro.alloc(token %0)
%6 = alloca i8, i64 %2, align 1
%7 = call ptr @llvm.coro.begin(token %0, ptr %6)
call void @llvm.coro.resume(ptr %7)
%8 = call i1 @llvm.coro.done(ptr %7)
%9 = zext i1 %8 to i64
%10 = trunc i64 %9 to i8
call void @llvm.coro.destroy(ptr %7)
%11 = call ptr @llvm.coro.promise(ptr null, i32 8, i1 false)
%12 = call ptr @llvm.coro.noop()
%13 = call ptr @llvm.coro.frame()
call void @setValue(ptr null, i64 1)
%14 = call i8 @llvm.coro.suspend(<null operand!>, i1 false)
switch i8 %14, label %suspend [
i8 0, label %suspend
i8 1, label %clean
]
suspend: ; preds = %entry, %entry, %clean
%15 = call i1 @llvm.coro.end(ptr %7, i1 false, token none)
call void @setValue(ptr null, i64 1)
br label %clean
clean: ; preds = %suspend, %entry
%16 = call ptr @llvm.coro.free(token %0, ptr %6)
br label %suspend
_llgo_3: ; No predecessors!
}
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: read)
declare token @llvm.coro.id(i32, ptr readnone, ptr nocapture readonly, ptr)
; Function Attrs: nounwind memory(none)
declare i32 @llvm.coro.size.i32()
; Function Attrs: nounwind memory(none)
declare i64 @llvm.coro.size.i64()
; Function Attrs: nounwind memory(none)
declare i32 @llvm.coro.align.i32()
; Function Attrs: nounwind memory(none)
declare i64 @llvm.coro.align.i64()
; Function Attrs: nounwind
declare i1 @llvm.coro.alloc(token)
; Function Attrs: nounwind
declare ptr @llvm.coro.begin(token, ptr writeonly)
; Function Attrs: nounwind memory(argmem: read)
declare ptr @llvm.coro.free(token, ptr nocapture readonly)
; Function Attrs: nounwind
declare i1 @llvm.coro.end(ptr, i1, token)
declare void @llvm.coro.resume(ptr)
; Function Attrs: nounwind memory(argmem: readwrite)
declare i1 @llvm.coro.done(ptr nocapture readonly)
declare void @llvm.coro.destroy(ptr)
; Function Attrs: nounwind memory(none)
declare ptr @llvm.coro.promise(ptr nocapture, i32, i1)
; Function Attrs: nounwind memory(none)
declare ptr @llvm.coro.noop()
; Function Attrs: nounwind memory(none)
declare ptr @llvm.coro.frame()
declare void @setValue(i64)
; Function Attrs: nounwind
declare i8 @llvm.coro.suspend(token, i1)
`)
}

View File

@@ -63,13 +63,6 @@ type aBuilder struct {
Func Function Func Function
Pkg Package Pkg Package
Prog Program Prog Program
async bool
asyncToken Expr
promise Expr
onSuspBlk func(blk BasicBlock) (susp BasicBlock, next BasicBlock, clean BasicBlock)
onReturn func()
blkOffset int
} }
// Builder represents a builder for creating instructions in a function. // Builder represents a builder for creating instructions in a function.
@@ -101,7 +94,7 @@ func (b Builder) setBlockMoveLast(blk BasicBlock) (next BasicBlock) {
impl := b.impl impl := b.impl
next = b.Func.MakeBlock("") next = b.Func.MakeBlock()
impl.SetInsertPointAtEnd(next.last) impl.SetInsertPointAtEnd(next.last)
impl.Insert(last) impl.Insert(last)
@@ -295,7 +288,7 @@ func (b Builder) Times(n Expr, loop func(i Expr)) {
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
/*
type caseStmt struct { type caseStmt struct {
v llvm.Value v llvm.Value
blk llvm.BasicBlock blk llvm.BasicBlock
@@ -333,7 +326,7 @@ func (b Builder) Switch(v Expr, defb BasicBlock) Switch {
} }
return &aSwitch{v.impl, defb.first, nil} return &aSwitch{v.impl, defb.first, nil}
} }
*/
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Phi represents a phi node. // Phi represents a phi node.

View File

@@ -58,7 +58,6 @@ const (
vkIface vkIface
vkStruct vkStruct
vkChan vkChan
vkToken
) )
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -283,13 +282,6 @@ func (p Program) tyInt() llvm.Type {
return p.intType return p.intType
} }
func (p Program) tyToken() llvm.Type {
if p.tokenType.IsNil() {
p.tokenType = p.ctx.TokenType()
}
return p.tokenType
}
func llvmIntType(ctx llvm.Context, size int) llvm.Type { func llvmIntType(ctx llvm.Context, size int) llvm.Type {
if size <= 4 { if size <= 4 {
return ctx.Int32Type() return ctx.Int32Type()
@@ -370,9 +362,6 @@ func (p Program) toType(raw types.Type) Type {
return &aType{p.rtString(), typ, vkString} return &aType{p.rtString(), typ, vkString}
case types.UnsafePointer: case types.UnsafePointer:
return &aType{p.tyVoidPtr(), typ, vkPtr} return &aType{p.tyVoidPtr(), typ, vkPtr}
// TODO(lijie): temporary solution, should be replaced by a proper type
case types.Invalid:
return &aType{p.tyToken(), typ, vkInvalid}
} }
case *types.Pointer: case *types.Pointer:
elem := p.rawType(t.Elem()) elem := p.rawType(t.Elem())
@@ -455,8 +444,7 @@ func (p Program) toLLVMTypes(t *types.Tuple, n int) (ret []llvm.Type) {
if n > 0 { if n > 0 {
ret = make([]llvm.Type, n) ret = make([]llvm.Type, n)
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
pt := t.At(i) ret[i] = p.rawType(t.At(i).Type()).ll
ret[i] = p.rawType(pt.Type()).ll
} }
} }
return return

View File

@@ -1,229 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"log"
"strings"
"time"
"github.com/goplus/llgo/x/async"
"github.com/goplus/llgo/x/tuple"
)
// -----------------------------------------------------------------------------
func http(method string, url string, callback func(resp *Response, err error)) {
go func() {
body := ""
if strings.HasPrefix(url, "http://example.com/user/") {
name := url[len("http://example.com/user/"):]
body = `{"name":"` + name + `"}`
} else if strings.HasPrefix(url, "http://example.com/score/") {
body = "99.5"
}
time.Sleep(200 * time.Millisecond)
resp := &Response{StatusCode: 200, Body: body}
callback(resp, nil)
}()
}
// -----------------------------------------------------------------------------
type Response struct {
StatusCode int
Body string
}
func (r *Response) Text() (co async.Promise[tuple.Tuple2[string, error]]) {
co.Return(tuple.Tuple2[string, error]{V1: r.Body, V2: nil})
return
}
// async AsyncHttpGet(url string) (resp *Response, err error) {
// http("GET", url, func(resp *Response, err error) {
// return resp, err
// })
// }
func AsyncHttpGet(url string) (co async.Promise[tuple.Tuple2[*Response, error]]) {
return co.Async(func(resolve func(tuple.Tuple2[*Response, error])) {
http("GET", url, func(resp *Response, err error) {
resolve(tuple.Tuple2[*Response, error]{V1: resp, V2: nil})
})
})
}
func AsyncHttpPost(url string) (co async.Promise[tuple.Tuple2[*Response, error]]) {
http("POST", url, func(resp *Response, err error) {
// co.Return(tuple.Tuple2[*Response, error]{V1: resp, V2: nil})
})
co.Suspend()
return
}
// -----------------------------------------------------------------------------
type User struct {
Name string
}
func GetUser(name string) (co async.Promise[tuple.Tuple2[User, error]]) {
resp, err := AsyncHttpGet("http://example.com/user/" + name).Await().Values()
if err != nil {
// return User{}, err
co.Return(tuple.Tuple2[User, error]{V1: User{}, V2: err})
return
}
if resp.StatusCode != 200 {
// return User{}, fmt.Errorf("http status code: %d", resp.StatusCode)
co.Return(tuple.Tuple2[User, error]{V1: User{}, V2: fmt.Errorf("http status code: %d", resp.StatusCode)})
return
}
body, err := resp.Text().Await().Values()
if err != nil {
// return User{}, err
co.Return(tuple.Tuple2[User, error]{V1: User{}, V2: err})
return
}
user := User{}
if err := json.Unmarshal([]byte(body), &user); err != nil {
// return User{}, err
co.Return(tuple.Tuple2[User, error]{V1: User{}, V2: err})
return
}
// return user, nil
co.Return(tuple.Tuple2[User, error]{V1: user, V2: nil})
return
}
func GetScore() (co *async.Promise[tuple.Tuple2[float64, error]]) {
resp, err := AsyncHttpGet("http://example.com/score/").Await().Values()
if err != nil {
co.Return(tuple.Tuple2[float64, error]{V1: 0, V2: err})
return
}
if resp.StatusCode != 200 {
// return 0, fmt.Errorf("http status code: %d", resp.StatusCode)
co.Return(tuple.Tuple2[float64, error]{V1: 0, V2: fmt.Errorf("http status code: %d", resp.StatusCode)})
return
}
body, err := resp.Text().Await().Values()
if err != nil {
// return 0, err
co.Return(tuple.Tuple2[float64, error]{V1: 0, V2: err})
return
}
score := 0.0
if _, err := fmt.Sscanf(body, "%f", &score); err != nil {
// return 0, err
co.Return(tuple.Tuple2[float64, error]{V1: 0, V2: err})
return
}
// return score, nil
co.Return(tuple.Tuple2[float64, error]{V1: score, V2: nil})
return
}
func DoUpdate(op string) (co *async.Promise[error]) {
resp, err := AsyncHttpPost("http://example.com/update/" + op).Await().Values()
if err != nil {
co.Return(err)
return
}
if resp.StatusCode != 200 {
co.Return(fmt.Errorf("http status code: %d", resp.StatusCode))
}
co.Return(nil)
return
}
func GenInts() (co *async.Promise[int]) {
co.Yield(3)
co.Yield(2)
co.Yield(5)
return
}
// Generator with async calls and panic
func GenUsers() (co *async.Promise[User]) {
u, err := GetUser("Alice").Await().Values()
if err != nil {
panic(err)
}
co.Yield(u)
u, err = GetUser("Bob").Await().Values()
if err != nil {
panic(err)
}
co.Yield(u)
u, err = GetUser("Cindy").Await().Values()
if err != nil {
panic(err)
}
co.Yield(u)
log.Printf("genUsers done\n")
return
}
func Demo() (co *async.Promise[async.Void]) {
user, err := GetUser("1").Await().Values()
log.Println(user, err)
// user, err = naive.Race[tuple.Tuple2[User, error]](GetUser("2"), GetUser("3"), GetUser("4")).Value().Values()
// log.Println(user, err)
// users := naive.All[tuple.Tuple2[User, error]]([]naive.AsyncCall[tuple.Tuple2[User, error]]{GetUser("5"), GetUser("6"), GetUser("7")}).Value()
// log.Println(users, err)
// user, score, _ := naive.Await3Compiled[User, float64, async.Void](GetUser("8"), GetScore(), DoUpdate("update sth.")).Value().Values()
// log.Println(user, score, err)
// for loop with generator
g := GenInts()
for !g.Done() {
log.Println("genInt:", g.Value(), g.Done())
g.Resume()
}
// for loop with async generator
// for u, err := range GenUsers() {...}
g1 := GenUsers()
for !g1.Done() {
u := g1.Value()
log.Println("genUser:", u)
g1.Resume()
}
// TODO(lijie): select from multiple promises without channel
// select {
// case user := <-GetUser("123").Chan():
// log.Println("user:", user)
// case score := <-GetScore().Chan():
// log.Println("score:", score)
// case <-async.Timeout(5 * time.Second).Chan():
// log.Println("timeout")
// }
log.Println("Demo done")
co.Return(async.Void{})
return
}
func main() {
log.SetFlags(log.Lshortfile | log.LstdFlags)
log.Printf("=========== Run Demo ===========\n")
v1 := Demo()
log.Println(v1)
log.Printf("=========== Run Demo finished ===========\n")
}

View File

@@ -1,26 +0,0 @@
package main
import (
"fmt"
"github.com/goplus/llgo/x/async"
)
func GenInts() (co *async.Promise[int]) {
println("gen: 1")
co.Yield(1)
println("gen: 2")
co.Yield(2)
println("gen: 3")
co.Yield(3)
return
}
func main() {
co := GenInts()
for !co.Done() {
fmt.Printf("got: %v\n", co.Value())
co.Next()
}
fmt.Printf("done\n")
}

View File

@@ -1,77 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package async
import (
"unsafe"
_ "unsafe"
)
const (
LLGoPackage = "decl"
)
type Void = [0]byte
// -----------------------------------------------------------------------------
type Promise[TOut any] struct {
hdl unsafe.Pointer
value TOut
}
// // llgo:link (*Promise).Await llgo.coAwait
func (p *Promise[TOut]) Await() TOut {
panic("should not executed")
}
func (p *Promise[TOut]) Return(v TOut) {
p.value = v
coReturn(p.hdl)
}
// llgo:link (*Promise).Yield llgo.coYield
func (p *Promise[TOut]) Yield(v TOut) {}
// llgo:link (*Promise).Suspend llgo.coSuspend
func (p *Promise[TOut]) Suspend() {}
func (p *Promise[TOut]) Resume() {
coResume(p.hdl)
}
func (p *Promise[TOut]) Next() {
coResume(p.hdl)
}
// TODO(lijie): should merge to Yield()
// call by llgo.coYield
func (p *Promise[TOut]) setValue(v TOut) {
p.value = v
}
func (p *Promise[TOut]) Value() TOut {
return p.value
}
func (p *Promise[TOut]) Done() bool {
return coDone(p.hdl) != 0
}
func Run[TOut any](f func() TOut) TOut {
panic("should not executed")
}

View File

@@ -0,0 +1,290 @@
package main
import (
"encoding/json"
"fmt"
"log"
"time"
"github.com/goplus/llgo/x/io"
)
// -----------------------------------------------------------------------------
type Response struct {
StatusCode int
mockBody string
}
func (r *Response) mock(body string) {
r.mockBody = body
}
func (r *Response) Text() (resolve io.Promise[string]) {
resolve(r.mockBody, nil)
return
}
func (r *Response) TextCompiled() *io.PromiseImpl[string] {
P := &io.PromiseImpl[string]{}
P.Func = func(resolve func(string, error)) {
for {
switch P.Prev = P.Next; P.Prev {
case 0:
resolve(r.mockBody, nil)
P.Next = -1
return
default:
panic("Promise already done")
}
}
}
return P
}
func HttpGet(url string, callback func(resp *Response, err error)) {
resp := &Response{StatusCode: 200}
callback(resp, nil)
}
func AsyncHttpGet(url string) (resolve io.Promise[*Response]) {
HttpGet(url, resolve)
return
}
func AsyncHttpGetCompiled(url string) *io.PromiseImpl[*Response] {
P := &io.PromiseImpl[*Response]{}
P.Func = func(resolve func(*Response, error)) {
for {
switch P.Prev = P.Next; P.Prev {
case 0:
HttpGet(url, resolve)
P.Next = -1
return
default:
panic("Promise already done")
}
}
}
return P
}
// -----------------------------------------------------------------------------
type User struct {
Name string
}
func GetUser(uid string) (resolve io.Promise[User]) {
resp, err := AsyncHttpGet("http://example.com/user/" + uid).Await()
if err != nil {
resolve(User{}, err)
return
}
if resp.StatusCode != 200 {
resolve(User{}, fmt.Errorf("http status code: %d", resp.StatusCode))
return
}
resp.mock(`{"name":"Alice"}`)
body, err := resp.Text().Await()
if err != nil {
resolve(User{}, err)
return
}
user := User{}
if err := json.Unmarshal([]byte(body), &user); err != nil {
resolve(User{}, err)
return
}
resolve(user, nil)
return
}
func GetUserCompiled(uid string) *io.PromiseImpl[User] {
var state1 *io.PromiseImpl[*Response]
var state2 *io.PromiseImpl[string]
P := &io.PromiseImpl[User]{}
P.Func = func(resolve func(User, error)) {
for {
switch P.Prev = P.Next; P.Prev {
case 0:
state1 = AsyncHttpGetCompiled("http://example.com/user/" + uid)
P.Next = 1
return
case 1:
state1.EnsureDone()
resp, err := state1.Value, state1.Err
if err != nil {
resolve(User{}, err)
return
}
if resp.StatusCode != 200 {
resolve(User{}, fmt.Errorf("http status code: %d", resp.StatusCode))
return
}
resp.mock(`{"name":"Alice"}`)
state2 = resp.TextCompiled()
P.Next = 2
return
case 2:
state2.EnsureDone()
body, err := state2.Value, state2.Err
if err != nil {
resolve(User{}, err)
return
}
user := User{}
if err := json.Unmarshal([]byte(body), &user); err != nil {
resolve(User{}, err)
return
}
resolve(user, nil)
P.Next = -1
return
default:
panic("Promise already done")
}
}
}
return P
}
func GetScore() *io.Promise[float64] {
panic("todo: GetScore")
}
func GetScoreCompiled() *io.PromiseImpl[float64] {
P := &io.PromiseImpl[float64]{}
P.Func = func(resolve func(float64, error)) {
for {
switch P.Prev = P.Next; P.Prev {
case 0:
panic("todo: GetScore")
default:
panic("Promise already done")
}
}
}
return P
}
func DoUpdate(op string) *io.Promise[io.Void] {
panic("todo: DoUpdate")
}
func DoUpdateCompiled(op string) *io.PromiseImpl[io.Void] {
P := &io.PromiseImpl[io.Void]{}
P.Func = func(resolve func(io.Void, error)) {
for {
switch P.Prev = P.Next; P.Prev {
case 0:
panic("todo: DoUpdate")
default:
panic("Promise already done")
}
}
}
return P
}
func Demo() (resolve io.Promise[io.Void]) {
user, err := GetUser("123").Await()
log.Println(user, err)
user, err = io.Race[User](GetUser("123"), GetUser("456"), GetUser("789")).Await()
log.Println(user, err)
users, err := io.All[User]([]io.AsyncCall[User]{GetUser("123"), GetUser("456"), GetUser("789")}).Await()
log.Println(users, err)
user, score, _, err := io.Await3[User, float64, io.Void](GetUser("123"), GetScore(), DoUpdate("update sth."))
log.Println(user, score, err)
// TODO(lijie): select from multiple promises without channel
select {
case user := <-GetUser("123").Chan():
log.Println("user:", user)
case score := <-GetScore().Chan():
log.Println("score:", score)
case <-io.Timeout(5 * time.Second).Chan():
log.Println("timeout")
}
return
}
func DemoCompiled() *io.PromiseImpl[io.Void] {
var state1 *io.PromiseImpl[User]
var state2 *io.PromiseImpl[User]
var state3 *io.PromiseImpl[[]User]
var state4 *io.PromiseImpl[io.Await3Result[User, float64, io.Void]]
P := &io.PromiseImpl[io.Void]{}
P.Func = func(resolve func(io.Void, error)) {
for {
switch P.Prev = P.Next; P.Prev {
case 0:
state1 = GetUserCompiled("123")
P.Next = 1
return
case 1:
state1.EnsureDone()
user, err := state1.Value, state1.Err
log.Printf("user: %v, err: %v\n", user, err)
state2 = io.Race[User](GetUserCompiled("123"), GetUserCompiled("456"), GetUserCompiled("789"))
P.Next = 2
return
case 2:
state2.EnsureDone()
user, err := state2.Value, state2.Err
log.Println(user, err)
state3 = io.All[User]([]io.AsyncCall[User]{GetUserCompiled("123"), GetUserCompiled("456"), GetUserCompiled("789")})
P.Next = 3
return
case 3:
state3.EnsureDone()
users, err := state3.Value, state3.Err
log.Println(users, err)
state4 = io.Await3Compiled[User, float64, io.Void](GetUserCompiled("123"), GetScoreCompiled(), DoUpdateCompiled("update sth."))
P.Next = 4
return
case 4:
state4.EnsureDone()
user, score, _, err := state4.Value.V1, state4.Value.V2, state4.Value.V3, state4.Value.Err
log.Println(user, score, err)
select {
case user := <-GetUserCompiled("123").Chan():
log.Println("user:", user)
case score := <-GetScoreCompiled().Chan():
log.Println("score:", score)
case <-io.TimeoutCompiled(5 * time.Second).Chan():
log.Println("timeout")
}
P.Next = -1
return
default:
panic("Promise already done")
}
}
}
return P
}
func main() {
log.SetFlags(log.Lshortfile | log.LstdFlags)
// io.Run(Demo())
io.Run(DemoCompiled())
}

170
x/io/io.go Normal file
View File

@@ -0,0 +1,170 @@
/*
* 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 io
import (
_ "unsafe"
"time"
)
const (
LLGoPackage = "decl"
)
type Void = [0]byte
// -----------------------------------------------------------------------------
type AsyncCall[OutT any] interface {
Await(timeout ...time.Duration) (ret OutT, err error)
Chan() <-chan OutT
EnsureDone()
}
// llgo:link AsyncCall.Await llgo.await
func Await[OutT any](call AsyncCall[OutT], timeout ...time.Duration) (ret OutT, err error) {
return
}
//go:linkname Timeout llgo.timeout
func Timeout(time.Duration) (ret AsyncCall[Void])
func TimeoutCompiled(d time.Duration) *PromiseImpl[Void] {
P := &PromiseImpl[Void]{}
P.Func = func(resolve func(Void, error)) {
go func() {
time.Sleep(d)
resolve(Void{}, nil)
}()
}
return P
}
// llgo:link Race llgo.race
func Race[OutT any](acs ...AsyncCall[OutT]) (ret *PromiseImpl[OutT]) {
return
}
func All[OutT any](acs []AsyncCall[OutT]) (ret *PromiseImpl[[]OutT]) {
return nil
}
// llgo:link Await2 llgo.await
func Await2[OutT1, OutT2 any](
ac1 AsyncCall[OutT1], ac2 AsyncCall[OutT2],
timeout ...time.Duration) (ret1 OutT1, ret2 OutT2, err error) {
return
}
type Await2Result[T1 any, T2 any] struct {
V1 T1
V2 T2
Err error
}
func Await2Compiled[OutT1, OutT2 any](
ac1 AsyncCall[OutT1], ac2 AsyncCall[OutT2],
timeout ...time.Duration) (ret *PromiseImpl[Await2Result[OutT1, OutT2]]) {
return
}
// llgo:link Await3 llgo.await
func Await3[OutT1, OutT2, OutT3 any](
ac1 AsyncCall[OutT1], ac2 AsyncCall[OutT2], ac3 AsyncCall[OutT3],
timeout ...time.Duration) (ret1 OutT1, ret2 OutT2, ret3 OutT3, err error) {
return
}
type Await3Result[T1 any, T2 any, T3 any] struct {
V1 T1
V2 T2
V3 T3
Err error
}
func Await3Compiled[OutT1, OutT2, OutT3 any](
ac1 AsyncCall[OutT1], ac2 AsyncCall[OutT2], ac3 AsyncCall[OutT3],
timeout ...time.Duration) (ret *PromiseImpl[Await3Result[OutT1, OutT2, OutT3]]) {
return
}
func Run(ac AsyncCall[Void]) {
p := ac.(*PromiseImpl[Void])
p.Resume()
<-ac.Chan()
}
// -----------------------------------------------------------------------------
type Promise[OutT any] func(OutT, error)
// llgo:link Promise.Await llgo.await
func (p Promise[OutT]) Await(timeout ...time.Duration) (ret OutT, err error) {
return
}
func (p Promise[OutT]) Chan() <-chan OutT {
return nil
}
func (p Promise[OutT]) EnsureDone() {
}
// -----------------------------------------------------------------------------
type PromiseImpl[TOut any] struct {
Func func(resolve func(TOut, error))
Value TOut
Err error
Prev int
Next int
c chan TOut
}
func (p *PromiseImpl[TOut]) Resume() {
p.Func(func(v TOut, err error) {
p.Value = v
p.Err = err
})
}
func (p *PromiseImpl[TOut]) EnsureDone() {
if p.Next == -1 {
panic("Promise already done")
}
}
func (p *PromiseImpl[TOut]) Chan() <-chan TOut {
if p.c == nil {
p.c = make(chan TOut, 1)
p.Func(func(v TOut, err error) {
p.Value = v
p.Err = err
p.c <- v
})
}
return p.c
}
func (p *PromiseImpl[TOut]) Await(timeout ...time.Duration) (ret TOut, err error) {
panic("should not called")
}
// -----------------------------------------------------------------------------

View File

@@ -1,57 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package tuple
// -----------------------------------------------------------------------------
type Tuple1[T any] struct {
V1 T
}
func (r Tuple1[T]) Values() T {
return r.V1
}
type Tuple2[T1 any, T2 any] struct {
V1 T1
V2 T2
}
func (r Tuple2[T1, T2]) Values() (T1, T2) {
return r.V1, r.V2
}
type Tuple3[T1 any, T2 any, T3 any] struct {
V1 T1
V2 T2
V3 T3
}
func (r Tuple3[T1, T2, T3]) Values() (T1, T2, T3) {
return r.V1, r.V2, r.V3
}
type Tuple4[T1 any, T2 any, T3 any, T4 any] struct {
V1 T1
V2 T2
V3 T3
V4 T4
}
func (r Tuple4[T1, T2, T3, T4]) Values() (T1, T2, T3, T4) {
return r.V1, r.V2, r.V3, r.V4
}