Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions _demo/go/export/export.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"fmt"
"runtime"
"unsafe"

Expand Down Expand Up @@ -134,6 +135,11 @@ func RunGoroutine(value int) int {
return <-ch
}

//export FormatValue
func FormatValue(value string, number int) string {
return fmt.Sprintf("%s:%d", value, number)
}

// Functions with small struct parameters and return values

//export CreateSmallStruct
Expand Down
6 changes: 6 additions & 0 deletions _demo/go/export/libexport.h.want
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ mul(float a, float b);
void
github_com_goplus_llgo__demo_go_export_c_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/_demo/go/export/c.init")

intptr_t
AllThreadsSyscallStatus(void);

main_ComplexData
CreateComplexData(void);

Expand Down Expand Up @@ -163,6 +166,9 @@ CreateStringMap(void);
C_XType
CreateXType(int32_t id, GoString name, double value, _Bool flag);

GoString
FormatValue(GoString value, intptr_t number);

main_FuncInfoResult
GetFuncInfo(void);

Expand Down
28 changes: 28 additions & 0 deletions _demo/go/export/runtime_hooks_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//go:build linux

package main

import "syscall"

func gettimeofdayStatus() int {
var tv syscall.Timeval
if err := syscall.Gettimeofday(&tv); err != nil {
if errno, ok := err.(syscall.Errno); ok {
return int(errno)
}
return int(syscall.EINVAL)
}
if tv.Sec <= 0 {
return int(syscall.EINVAL)
}
return 0
}

//export AllThreadsSyscallStatus
func AllThreadsSyscallStatus() int {
if status := gettimeofdayStatus(); status != 0 {
return status
}
_, _, err := syscall.AllThreadsSyscall(syscall.SYS_GETPID, 0, 0, 0)
return int(err)
}
8 changes: 8 additions & 0 deletions _demo/go/export/runtime_hooks_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//go:build !linux

package main

//export AllThreadsSyscallStatus
func AllThreadsSyscallStatus() int {
return 0
}
3 changes: 2 additions & 1 deletion _demo/go/export/use/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ else
SHARED_EXT = so
PLATFORM_LIBS = $(shell pkg-config --libs libunwind 2>/dev/null || echo -lunwind)
endif
STATIC_STDLIB_LIBS = $(shell pkg-config --libs libffi 2>/dev/null || echo -lffi) -lresolv

# Library and flags based on link type
ifeq ($(LINK_TYPE),shared)
Expand All @@ -35,7 +36,7 @@ ifeq ($(LINK_TYPE),shared)
else
BUILDMODE = c-archive
LIBRARY = ../libexport.a
LDFLAGS = $(LIBRARY) $(RUNTIME_LIBS) $(PLATFORM_LIBS)
LDFLAGS = $(LIBRARY) $(RUNTIME_LIBS) $(PLATFORM_LIBS) $(STATIC_STDLIB_LIBS)
BUILD_MSG = "Building Go static library..."
LINK_MSG = "Linking with static library..."
endif
Expand Down
11 changes: 11 additions & 0 deletions _demo/go/export/use/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <stdlib.h>
#include <inttypes.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include "../libexport.h"

Expand Down Expand Up @@ -59,6 +60,16 @@ int main() {
HelloWorld();
printf("\n");

// Verify that a C library can initialize and call standard-library paths
// that depend on the runtime hooks supplied by LLGo.
GoString formatted = FormatValue((GoString){"answer", 6}, 42);
assert(go_string_equals(formatted, "answer:42"));
#ifdef __linux__
assert(AllThreadsSyscallStatus() == ENOTSUP);
#else
assert(AllThreadsSyscallStatus() == 0);
#endif

// Test small struct
main_SmallStruct small = CreateSmallStruct(5, 1); // 1 for true
assert(small.ID == 5);
Expand Down
16 changes: 12 additions & 4 deletions cl/_testdata/cpkg/in.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,25 @@ package C

// CHECK-LABEL: define double @Double(double %0){{.*}} {
// CHECK-NEXT: _llgo_0:
// CHECK-NEXT: %1 = fmul double 2.000000e+00, %0
// CHECK-NEXT: ret double %1
// CHECK-NEXT: %1 = alloca %"{{.*}}LocalContext", align 8
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr %1, i8 0, i64 8, i1 false)
// CHECK-NEXT: %2 = call i64 @"{{.*}}EnterLocalContext"(ptr %1)
// CHECK-NEXT: %3 = fmul double 2.000000e+00, %0
// CHECK-NEXT: call void @"{{.*}}LeaveLocalContext"(ptr %1, i64 %2)
// CHECK-NEXT: ret double %3
// CHECK-NEXT: }
func Double(x float64) float64 {
return 2 * x
}

// CHECK-LABEL: define i64 @add(i64 %0, i64 %1){{.*}} {
// CHECK-NEXT: _llgo_0:
// CHECK-NEXT: %2 = call i64 @"{{.*}}.add"(i64 %0, i64 %1)
// CHECK-NEXT: ret i64 %2
// CHECK-NEXT: %2 = alloca %"{{.*}}LocalContext", align 8
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr %2, i8 0, i64 8, i1 false)
// CHECK-NEXT: %3 = call i64 @"{{.*}}EnterLocalContext"(ptr %2)
// CHECK-NEXT: %4 = call i64 @"{{.*}}.add"(i64 %0, i64 %1)
// CHECK-NEXT: call void @"{{.*}}LeaveLocalContext"(ptr %2, i64 %3)
// CHECK-NEXT: ret i64 %4
// CHECK-NEXT: }
func Xadd(a, b int) int {
return add(a, b)
Expand Down
26 changes: 17 additions & 9 deletions cl/_testgo/goroutine/in.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,28 @@ func main() {

// CHECK-LABEL: define ptr @"{{.*}}goroutine._llgo_routine$1"(ptr %0){{.*}} {
// CHECK-NEXT: _llgo_0:
// CHECK-NEXT: %1 = load { %"{{.*}}String" }, ptr %0, align 8
// CHECK-NEXT: %2 = extractvalue { %"{{.*}}String" } %1, 0
// CHECK-NEXT: %1 = alloca %"{{.*}}LocalContext", align 8
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr %1, i8 0, i64 8, i1 false)
// CHECK-NEXT: %2 = call i64 @"{{.*}}EnterLocalContext"(ptr %1)
// CHECK-NEXT: %3 = load { %"{{.*}}String" }, ptr %0, align 8
// CHECK-NEXT: %4 = extractvalue { %"{{.*}}String" } %3, 0
// CHECK-NEXT: call void @"{{.*}}FreeRoot"(ptr %0)
// CHECK-NEXT: call void @"{{.*}}PrintString"(%"{{.*}}String" %2)
// CHECK-NEXT: call void @"{{.*}}PrintString"(%"{{.*}}String" %4)
// CHECK-NEXT: call void @"{{.*}}PrintByte"(i8 10)
// CHECK-NEXT: call void @"{{.*}}LeaveLocalContext"(ptr %1, i64 %2)
// CHECK-NEXT: ret ptr null

// CHECK-LABEL: define ptr @"{{.*}}goroutine._llgo_routine$2"(ptr %0){{.*}} {
// CHECK-NEXT: _llgo_0:
// CHECK-NEXT: %1 = load { { ptr, ptr }, %"{{.*}}String" }, ptr %0, align 8
// CHECK-NEXT: %2 = extractvalue { { ptr, ptr }, %"{{.*}}String" } %1, 0
// CHECK-NEXT: %3 = extractvalue { { ptr, ptr }, %"{{.*}}String" } %1, 1
// CHECK-NEXT: %1 = alloca %"{{.*}}LocalContext", align 8
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr %1, i8 0, i64 8, i1 false)
// CHECK-NEXT: %2 = call i64 @"{{.*}}EnterLocalContext"(ptr %1)
// CHECK-NEXT: %3 = load { { ptr, ptr }, %"{{.*}}String" }, ptr %0, align 8
// CHECK-NEXT: %4 = extractvalue { { ptr, ptr }, %"{{.*}}String" } %3, 0
// CHECK-NEXT: %5 = extractvalue { { ptr, ptr }, %"{{.*}}String" } %3, 1
// CHECK-NEXT: call void @"{{.*}}FreeRoot"(ptr %0)
// CHECK-NEXT: %4 = extractvalue { ptr, ptr } %2, 1
// CHECK-NEXT: %5 = extractvalue { ptr, ptr } %2, 0
// CHECK-NEXT: call void %5(ptr %4, %"{{.*}}String" %3)
// CHECK-NEXT: %6 = extractvalue { ptr, ptr } %4, 1
// CHECK-NEXT: %7 = extractvalue { ptr, ptr } %4, 0
// CHECK-NEXT: call void %7(ptr %6, %"{{.*}}String" %5)
// CHECK-NEXT: call void @"{{.*}}LeaveLocalContext"(ptr %1, i64 %2)
// CHECK-NEXT: ret ptr null
77 changes: 77 additions & 0 deletions cl/_testgo/localitycodegen/in.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// LITTEST
package main

// CHECK-DAG: @"{{.*}}localitycodegen.scalar" = thread_local global i64 0
// CHECK-DAG: @"{{.*}}localitycodegen.__llgo_local_cache" = thread_local global i64 0
// CHECK-DAG: @"{{.*}}localitycodegen.__llgo_tls_init$guard" = thread_local global i8 0
// CHECK-DAG: @"{{.*}}localitycodegen.__llgo_tls_init$failure_cache" = thread_local global i64 0
// CHECK-NOT: RegisterLocalRoot
// CHECK-NOT: localitycodegen.pointer" = thread_local
// CHECK-NOT: localitycodegen.initialized" = thread_local

// CHECK-LABEL: define ptr @"{{.*}}localitycodegen.__llgo_local_block"()
// CHECK: load i64, ptr @"{{.*}}localitycodegen.__llgo_local_cache"
// CHECK: icmp ne i64
// CHECK: ret ptr
// CHECK: call ptr @"{{.*}}runtime.LocalPackage"(ptr @"{{.*}}localitycodegen.__llgo_local_cache", i64 16, i64 8)
// CHECK: ret ptr

// CHECK-LABEL: define void @"{{.*}}localitycodegen.__llgo_tls_init"()
// CHECK: call void @"{{.*}}localitycodegen.__llgo_local_init_0"()

// CHECK-LABEL: define void @"{{.*}}localitycodegen.__llgo_tls_init$ensure"()
// CHECK: load i8, ptr
// CHECK: call void @"{{.*}}runtime.EnsureLocalInitializer"(ptr @"{{.*}}localitycodegen.__llgo_tls_init$guard", ptr @"{{.*}}localitycodegen.__llgo_tls_init$failure_cache"

// CHECK-LABEL: define ptr @{{"?ExportedLocality"?}}()
// CHECK: call i64 @"{{.*}}EnterLocalContext"
// CHECK: call ptr @"{{.*}}localitycodegen.__llgo_local_block"()
// CHECK: call void @"{{.*}}LeaveLocalContext"
// CHECK: ret ptr

// CHECK-LABEL: define void @"{{.*}}localitycodegen.init"()
// CHECK: store i8 2, ptr
// CHECK: call ptr @"{{.*}}localitycodegen.newPointer"()
// CHECK: call void @"{{.*}}localitycodegen.__llgo_tls_init$ensure"()
// CHECK: call ptr @"{{.*}}localitycodegen.__llgo_local_block"()

// CHECK-LABEL: define { i64, ptr, ptr } @"{{.*}}localitycodegen.values"()
// CHECK: call void @"{{.*}}localitycodegen.__llgo_tls_init$ensure"()
// CHECK: load i64, ptr @"{{.*}}localitycodegen.scalar"
// CHECK: call ptr @"{{.*}}localitycodegen.__llgo_local_block"()
// CHECK: load ptr, ptr
// CHECK: load ptr, ptr

// CHECK-LABEL: define ptr @"{{.*}}localitycodegen._llgo_routine$1"(ptr %0)
// CHECK: alloca %"{{.*}}LocalContext", align 8
// CHECK: call i64 @"{{.*}}EnterLocalContext"
// CHECK: call void @"{{.*}}LeaveLocalContext"

var backing int

func newPointer() *int {
return &backing
}

//llgo:tls
var scalar int

//llgo:gls
var pointer *int

//llgo:tls
var initialized = newPointer()

func values() (int, *int, *int) {
return scalar, pointer, initialized
}

//export ExportedLocality
func ExportedLocality() *int {
return pointer
}

func main() {
_, _, _ = values()
go values()
}
14 changes: 9 additions & 5 deletions cl/_testgo/selects/in.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,11 +234,15 @@ func main() {

// CHECK-LABEL: define ptr @"{{.*}}/cl/_testgo/selects._llgo_routine$1"(ptr %0){{.*}} {
// CHECK-NEXT: _llgo_0:
// CHECK-NEXT: %1 = load { { ptr, ptr } }, ptr %0, align 8
// CHECK-NEXT: %2 = extractvalue { { ptr, ptr } } %1, 0
// CHECK-NEXT: %1 = alloca %"{{.*}}/runtime/internal/runtime.LocalContext", align 8
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr %1, i8 0, i64 8, i1 false)
// CHECK-NEXT: %2 = call i64 @"{{.*}}/runtime/internal/runtime.EnterLocalContext"(ptr %1)
// CHECK-NEXT: %3 = load { { ptr, ptr } }, ptr %0, align 8
// CHECK-NEXT: %4 = extractvalue { { ptr, ptr } } %3, 0
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.FreeRoot"(ptr %0)
// CHECK-NEXT: %3 = extractvalue { ptr, ptr } %2, 1
// CHECK-NEXT: %4 = extractvalue { ptr, ptr } %2, 0
// CHECK-NEXT: call void %4(ptr %3)
// CHECK-NEXT: %5 = extractvalue { ptr, ptr } %4, 1
// CHECK-NEXT: %6 = extractvalue { ptr, ptr } %4, 0
// CHECK-NEXT: call void %6(ptr %5)
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.LeaveLocalContext"(ptr %1, i64 %2)
// CHECK-NEXT: ret ptr null
// CHECK-NEXT: }
Loading
Loading