diff --git a/go.mod b/go.mod index e5162166fb..179545ed0f 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( ) require ( - github.com/goplus/plan9asm v0.0.0-20260307134905-822503d6bf44 + github.com/goplus/plan9asm v0.1.1-0.20260314085947-7f506d4eb357 github.com/marcinbor85/gohex v0.0.0-20210308104911-55fb1c624d84 github.com/mattn/go-tty v0.0.7 github.com/sigurn/crc16 v0.0.0-20240131213347-83fcde1e29d1 diff --git a/go.sum b/go.sum index 25b6036285..16f9011ee8 100644 --- a/go.sum +++ b/go.sum @@ -14,14 +14,8 @@ github.com/goplus/llvm v0.8.7 h1:FUpjuZ4Y+F9wNw2ztN5dCGnZnAQgH1YHaYEiX2QpfkQ= github.com/goplus/llvm v0.8.7/go.mod h1:PeVK8GgzxwAYCiMiUAJb5wJR6xbhj989tu9oulKLLT4= github.com/goplus/mod v0.19.5 h1:36sbRxKie2Or9aSfWT06X6WV37sBwARXYfKfGfHzEQs= github.com/goplus/mod v0.19.5/go.mod h1:T6Ta3xPXx8NQaRb8h632P5iBgIB77zXfh9vLNRFqMqk= -github.com/goplus/plan9asm v0.0.0-20260212064924-71ea5584065b h1:DFZ0n92lGC3ogziCvtAHK8TKJf7oqiT4U576TIENiyk= -github.com/goplus/plan9asm v0.0.0-20260212064924-71ea5584065b/go.mod h1:nnr49+IlbnOI5c0yb1fkbilBRcr50RPX0JAreDdYTUI= -github.com/goplus/plan9asm v0.0.0-20260306151730-9203c54dfd4c h1:1S6F8dDxAnRiZAhqKjzLhAdx71jOaB5YdlHzfwCkdH8= -github.com/goplus/plan9asm v0.0.0-20260306151730-9203c54dfd4c/go.mod h1:nnr49+IlbnOI5c0yb1fkbilBRcr50RPX0JAreDdYTUI= -github.com/goplus/plan9asm v0.0.0-20260307044640-a5f1e3b27fc1 h1:hlVAtc3x34x6CQoOPnkOtz9p4juJ+cEZzgDyJpWnit4= -github.com/goplus/plan9asm v0.0.0-20260307044640-a5f1e3b27fc1/go.mod h1:nnr49+IlbnOI5c0yb1fkbilBRcr50RPX0JAreDdYTUI= -github.com/goplus/plan9asm v0.0.0-20260307134905-822503d6bf44 h1:zZXTz5CBO1uZIJGZSGWov5gE1CbulJ1QH6ruTMv3UdY= -github.com/goplus/plan9asm v0.0.0-20260307134905-822503d6bf44/go.mod h1:gpS4VVNoRykYTtc8kPFBowraN5SrBj8lIjW8/lNjaG4= +github.com/goplus/plan9asm v0.1.1-0.20260314085947-7f506d4eb357 h1:4typFkJN/D0YbNeNi5UIMoQdlWC+E4dn8goD4ddjMFs= +github.com/goplus/plan9asm v0.1.1-0.20260314085947-7f506d4eb357/go.mod h1:gpS4VVNoRykYTtc8kPFBowraN5SrBj8lIjW8/lNjaG4= github.com/marcinbor85/gohex v0.0.0-20210308104911-55fb1c624d84 h1:hyAgCuG5nqTMDeUD8KZs7HSPs6KprPgPP8QmGV8nyvk= github.com/marcinbor85/gohex v0.0.0-20210308104911-55fb1c624d84/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= diff --git a/internal/build/build.go b/internal/build/build.go index 84f254eac7..2e1a32758c 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -1253,10 +1253,12 @@ func buildPkg(ctx *context, aPkg *aPackage, verbose bool) error { } aPkg.ObjFiles = append(aPkg.ObjFiles, cgoLLFiles...) aPkg.ObjFiles = append(aPkg.ObjFiles, concatPkgLinkFiles(ctx, pkg, printCmds)...) - if asmObjFiles, err := compilePkgSFiles(ctx, aPkg, pkg, printCmds); err != nil { - return err - } else { - aPkg.ObjFiles = append(aPkg.ObjFiles, asmObjFiles...) + if aPkg.AltPkg == nil || llruntime.HasAdditiveAltPkg(pkgPath) { + if asmObjFiles, err := compilePkgSFiles(ctx, aPkg, pkg, printCmds); err != nil { + return err + } else { + aPkg.ObjFiles = append(aPkg.ObjFiles, asmObjFiles...) + } } if aliasObjs, err := buildGoCgoAliasObjects(ctx, pkgPath, aPkg.Package.Syntax, printCmds); err != nil { return err diff --git a/internal/build/plan9asm.go b/internal/build/plan9asm.go index 6d3f1df741..6faafbb42f 100644 --- a/internal/build/plan9asm.go +++ b/internal/build/plan9asm.go @@ -201,6 +201,10 @@ func plan9asmSigsForPkg(ctx *context, pkgPath string) (map[string]struct{}, erro plan9AsmSigCache.Store(key, sigs) return sigs, nil } + if hasAltPkgForTarget(ctx.buildConf, pkgPath) && !llruntime.HasAdditiveAltPkgForGOARCH(pkgPath, ctx.buildConf.Goarch) { + plan9AsmSigCache.Store(key, sigs) + return sigs, nil + } var pkg *packages.Package for p := range ctx.pkgs { @@ -297,10 +301,10 @@ func (ctx *context) plan9asmEnabled(pkgPath string) bool { } func hasAltPkgForTarget(conf *Config, pkgPath string) bool { - if !llruntime.HasAltPkg(pkgPath) { + if conf == nil || !llruntime.HasAltPkgForGOARCH(pkgPath, conf.Goarch) { return false } - if llruntime.HasAdditiveAltPkg(pkgPath) { + if llruntime.HasAdditiveAltPkgForGOARCH(pkgPath, conf.Goarch) { return true } // When Plan9 asm translation is enabled, avoid also pulling in alt packages @@ -334,7 +338,7 @@ func plan9asmEnabledByDefault(conf *Config, pkgPath string) bool { if !archSupportsPlan9AsmDefaults(conf.Goarch) { return false } - return !llruntime.HasAltPkg(pkgPath) || llruntime.HasAdditiveAltPkg(pkgPath) + return !llruntime.HasAltPkgForGOARCH(pkgPath, conf.Goarch) || llruntime.HasAdditiveAltPkgForGOARCH(pkgPath, conf.Goarch) } func pkgSFiles(ctx *context, pkg *packages.Package) ([]string, error) { @@ -403,14 +407,33 @@ func pkgSFiles(ctx *context, pkg *packages.Package) ([]string, error) { return paths, nil } } + // Embedded ARM targets currently reuse GOOS=linux metadata, but they do not + // have a Linux syscall surface. Skip syscall asm in that mode so embedded + // builds do not inherit Linux/ARM-specific frame layouts. + if shouldSkipPlan9AsmSFilesForTarget(ctx.buildConf, pkg.PkgPath) { + ctx.sfilesCache[pkg.ID] = nil + return nil, nil + } - paths := make([]string, 0, len(lp.SFiles)) - for _, f := range lp.SFiles { - if lp.Dir == "" { + paths := selectedSFiles(lp.Dir, lp.SFiles) + ctx.sfilesCache[pkg.ID] = paths + return paths, nil +} + +func selectedSFiles(dir string, files []string) []string { + if dir == "" || len(files) == 0 { + return nil + } + paths := make([]string, 0, len(files)) + for _, f := range files { + if strings.HasSuffix(f, "_test.s") || strings.HasSuffix(f, "_test.S") { continue } - paths = append(paths, filepath.Join(lp.Dir, f)) + paths = append(paths, filepath.Join(dir, f)) } - ctx.sfilesCache[pkg.ID] = paths - return paths, nil + return paths +} + +func shouldSkipPlan9AsmSFilesForTarget(conf *Config, pkgPath string) bool { + return conf != nil && conf.Target != "" && conf.Goarch == "arm" && pkgPath == "syscall" } diff --git a/internal/build/plan9asm_altpkg_test.go b/internal/build/plan9asm_altpkg_test.go index 982f3d1ad5..5d36caa635 100644 --- a/internal/build/plan9asm_altpkg_test.go +++ b/internal/build/plan9asm_altpkg_test.go @@ -18,3 +18,15 @@ func TestHasAltPkgForTarget_AllowsAdditivePatchWithPlan9Asm(t *testing.T) { t.Fatal("internal/runtime/sys should keep its additive alt package even when plan9asm is enabled") } } + +func TestHasAltPkgForTarget_UsesAtomicFallbackOnArm(t *testing.T) { + conf := &Config{Goarch: "arm", AbiMode: cabi.ModeAllFunc} + if !hasAltPkgForTarget(conf, "internal/runtime/atomic") { + t.Fatal("internal/runtime/atomic should use alt package on arm") + } + + conf = &Config{Goarch: "arm64", AbiMode: cabi.ModeAllFunc} + if hasAltPkgForTarget(conf, "internal/runtime/atomic") { + t.Fatal("internal/runtime/atomic should keep plan9asm/std paths on arm64") + } +} diff --git a/internal/build/plan9asm_sfiles_test.go b/internal/build/plan9asm_sfiles_test.go new file mode 100644 index 0000000000..e0f9978eb7 --- /dev/null +++ b/internal/build/plan9asm_sfiles_test.go @@ -0,0 +1,51 @@ +//go:build !llgo +// +build !llgo + +package build + +import ( + "path/filepath" + "reflect" + "testing" +) + +func TestSelectedSFilesSkipsTestAsm(t *testing.T) { + dir := "/tmp/pkg" + got := selectedSFiles(dir, []string{ + "abi_test.s", + "stub.s", + "helper.S", + "compare_test.S", + }) + want := []string{ + filepath.Join(dir, "stub.s"), + filepath.Join(dir, "helper.S"), + } + if !reflect.DeepEqual(got, want) { + t.Fatalf("selectedSFiles() = %#v, want %#v", got, want) + } +} + +func TestSelectedSFilesHandlesEmptyInput(t *testing.T) { + if got := selectedSFiles("", []string{"stub.s"}); got != nil { + t.Fatalf("selectedSFiles(empty dir) = %#v, want nil", got) + } + if got := selectedSFiles("/tmp/pkg", nil); got != nil { + t.Fatalf("selectedSFiles(nil files) = %#v, want nil", got) + } +} + +func TestShouldSkipPlan9AsmSFilesForTarget(t *testing.T) { + if !shouldSkipPlan9AsmSFilesForTarget(&Config{Target: "cortex-m-qemu", Goarch: "arm"}, "syscall") { + t.Fatal("embedded arm syscall asm should be skipped") + } + if shouldSkipPlan9AsmSFilesForTarget(&Config{Target: "", Goarch: "arm"}, "syscall") { + t.Fatal("host arm syscall asm should not be skipped") + } + if shouldSkipPlan9AsmSFilesForTarget(&Config{Target: "cortex-m-qemu", Goarch: "arm64"}, "syscall") { + t.Fatal("arm64 syscall asm should not be skipped by arm-only rule") + } + if shouldSkipPlan9AsmSFilesForTarget(&Config{Target: "cortex-m-qemu", Goarch: "arm"}, "internal/bytealg") { + t.Fatal("only syscall asm should be skipped by embedded arm rule") + } +} diff --git a/internal/plan9asm/bytealg_arm_sigs_test.go b/internal/plan9asm/bytealg_arm_sigs_test.go new file mode 100644 index 0000000000..2241d36f2e --- /dev/null +++ b/internal/plan9asm/bytealg_arm_sigs_test.go @@ -0,0 +1,85 @@ +//go:build !llgo +// +build !llgo + +package plan9asm + +import ( + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/goplus/llgo/internal/packages" + extplan9asm "github.com/goplus/plan9asm" +) + +func loadStdlibInternalBytealgForTarget(t *testing.T, goos, goarch string) *packages.Package { + t.Helper() + cfg := &packages.Config{ + Mode: packages.NeedName | packages.NeedFiles | packages.NeedSyntax | packages.NeedTypes | packages.NeedTypesSizes | packages.NeedTypesInfo | packages.NeedImports, + Env: append(os.Environ(), "GOOS="+goos, "GOARCH="+goarch), + } + pkgs, err := packages.LoadEx(nil, nil, cfg, "internal/bytealg") + if err != nil { + t.Fatal(err) + } + if len(pkgs) != 1 || pkgs[0].Types == nil { + t.Fatalf("load internal/bytealg: got %d pkgs, types=%v", len(pkgs), pkgs[0].Types) + } + return pkgs[0] +} + +func TestSigsForStdlibInternalBytealgArmHelpers(t *testing.T) { + goroot := runtime.GOROOT() + if goroot == "" { + t.Skip("GOROOT not available") + } + pkg := loadStdlibInternalBytealgForTarget(t, "linux", "arm") + + tests := map[string]map[string]extplan9asm.FuncSig{ + filepath.Join(goroot, "src", "internal", "bytealg", "compare_arm.s"): { + "internal/bytealg.cmpbody": { + Args: []extplan9asm.LLVMType{extplan9asm.Ptr, "i32", extplan9asm.Ptr, "i32", extplan9asm.Ptr}, + Ret: extplan9asm.Void, + ArgRegs: []extplan9asm.Reg{"R2", "R0", "R3", "R1", "R7"}, + }, + }, + filepath.Join(goroot, "src", "internal", "bytealg", "count_arm.s"): { + "internal/bytealg.countbytebody": { + Args: []extplan9asm.LLVMType{extplan9asm.Ptr, "i32", "i8", extplan9asm.Ptr}, + Ret: extplan9asm.Void, + ArgRegs: []extplan9asm.Reg{"R0", "R1", "R2", "R7"}, + }, + }, + filepath.Join(goroot, "src", "internal", "bytealg", "equal_arm.s"): { + "internal/bytealg.memeqbody": { + Args: []extplan9asm.LLVMType{extplan9asm.Ptr, extplan9asm.Ptr, "i32", extplan9asm.Ptr}, + Ret: extplan9asm.Void, + ArgRegs: []extplan9asm.Reg{"R0", "R2", "R1", "R7"}, + }, + }, + filepath.Join(goroot, "src", "internal", "bytealg", "indexbyte_arm.s"): { + "internal/bytealg.indexbytebody": { + Args: []extplan9asm.LLVMType{extplan9asm.Ptr, "i32", "i8", extplan9asm.Ptr}, + Ret: extplan9asm.Void, + ArgRegs: []extplan9asm.Reg{"R0", "R1", "R2", "R5"}, + }, + }, + } + + for path, wantSigs := range tests { + tr, err := TranslateFileForPkg(pkg, path, "linux", "arm", nil) + if err != nil { + t.Fatalf("translate %s: %v", path, err) + } + for name, want := range wantSigs { + got, ok := tr.Signatures[name] + if !ok { + t.Fatalf("missing symbol %s in %s", name, path) + } + if err := checkSig(got, want); err != nil { + t.Fatalf("%s (%s): %v", name, path, err) + } + } + } +} diff --git a/internal/plan9asm/translate.go b/internal/plan9asm/translate.go index dcc674c99e..5e53983450 100644 --- a/internal/plan9asm/translate.go +++ b/internal/plan9asm/translate.go @@ -195,6 +195,27 @@ func extraAsmSigsAndDeclMap(pkgPath string, goarch string) map[string]extplan9as manual := map[string]extplan9asm.FuncSig{} if pkgPath == "internal/bytealg" { switch goarch { + case "arm": + manual["internal/bytealg.cmpbody"] = extplan9asm.FuncSig{ + Args: []extplan9asm.LLVMType{extplan9asm.Ptr, "i32", extplan9asm.Ptr, "i32", extplan9asm.Ptr}, + Ret: extplan9asm.Void, + ArgRegs: []extplan9asm.Reg{"R2", "R0", "R3", "R1", "R7"}, + } + manual["internal/bytealg.memeqbody"] = extplan9asm.FuncSig{ + Args: []extplan9asm.LLVMType{extplan9asm.Ptr, extplan9asm.Ptr, "i32", extplan9asm.Ptr}, + Ret: extplan9asm.Void, + ArgRegs: []extplan9asm.Reg{"R0", "R2", "R1", "R7"}, + } + manual["internal/bytealg.countbytebody"] = extplan9asm.FuncSig{ + Args: []extplan9asm.LLVMType{extplan9asm.Ptr, "i32", "i8", extplan9asm.Ptr}, + Ret: extplan9asm.Void, + ArgRegs: []extplan9asm.Reg{"R0", "R1", "R2", "R7"}, + } + manual["internal/bytealg.indexbytebody"] = extplan9asm.FuncSig{ + Args: []extplan9asm.LLVMType{extplan9asm.Ptr, "i32", "i8", extplan9asm.Ptr}, + Ret: extplan9asm.Void, + ArgRegs: []extplan9asm.Reg{"R0", "R1", "R2", "R5"}, + } case "arm64": manual["internal/bytealg.cmpbody"] = extplan9asm.FuncSig{Args: []extplan9asm.LLVMType{extplan9asm.Ptr, extplan9asm.I64, extplan9asm.Ptr, extplan9asm.I64}, Ret: extplan9asm.I64} manual["internal/bytealg.memeqbody"] = extplan9asm.FuncSig{Args: []extplan9asm.LLVMType{extplan9asm.Ptr, extplan9asm.Ptr, extplan9asm.I64}, Ret: extplan9asm.I1} diff --git a/internal/plan9asm/translate_helpers_test.go b/internal/plan9asm/translate_helpers_test.go index b43fb2b98c..91e2aa44fd 100644 --- a/internal/plan9asm/translate_helpers_test.go +++ b/internal/plan9asm/translate_helpers_test.go @@ -193,6 +193,18 @@ func TestExtraAsmSigsAndDeclMap(t *testing.T) { t.Fatalf("unexpected manual sigs for other/pkg: %#v", got) } + arm := extraAsmSigsAndDeclMap("internal/bytealg", "arm") + for _, name := range []string{ + "internal/bytealg.cmpbody", + "internal/bytealg.memeqbody", + "internal/bytealg.countbytebody", + "internal/bytealg.indexbytebody", + } { + if _, ok := arm[name]; !ok { + t.Fatalf("missing arm manual sig %s", name) + } + } + arm64 := extraAsmSigsAndDeclMap("internal/bytealg", "arm64") for _, name := range []string{ "internal/bytealg.cmpbody", diff --git a/runtime/build.go b/runtime/build.go index c2c6709c97..5f895ffd17 100644 --- a/runtime/build.go +++ b/runtime/build.go @@ -7,6 +7,23 @@ const ( altPkgAdditive ) +type altPkgSpec struct { + mode altPkgMode + goarchs map[string]struct{} +} + +func (s altPkgSpec) enabledFor(goarch string) bool { + return len(s.goarchs) == 0 || hasGoarch(s.goarchs, goarch) +} + +func hasGoarch(goarchs map[string]struct{}, goarch string) bool { + if goarchs == nil { + return false + } + _, ok := goarchs[goarch] + return ok +} + func SkipToBuild(pkgPath string) bool { if _, ok := altPkgs[pkgPath]; ok { return false @@ -19,19 +36,30 @@ func HasAltPkg(path string) (b bool) { return } +func HasAltPkgForGOARCH(path, goarch string) bool { + spec, ok := altPkgs[path] + return ok && spec.enabledFor(goarch) +} + func HasAdditiveAltPkg(path string) bool { - return altPkgs[path] == altPkgAdditive -} - -var altPkgs = map[string]altPkgMode{ - "internal/abi": altPkgReplace, - "internal/reflectlite": altPkgReplace, - "internal/runtime/maps": altPkgReplace, - "internal/runtime/sys": altPkgAdditive, - "iter": altPkgReplace, - "reflect": altPkgReplace, - "runtime": altPkgReplace, - "unique": altPkgReplace, - "syscall/js": altPkgReplace, - "sync/atomic": altPkgReplace, + return altPkgs[path].mode == altPkgAdditive +} + +func HasAdditiveAltPkgForGOARCH(path, goarch string) bool { + spec, ok := altPkgs[path] + return ok && spec.mode == altPkgAdditive && spec.enabledFor(goarch) +} + +var altPkgs = map[string]altPkgSpec{ + "internal/abi": {mode: altPkgReplace}, + "internal/runtime/atomic": {mode: altPkgReplace, goarchs: map[string]struct{}{"arm": {}}}, + "internal/reflectlite": {mode: altPkgReplace}, + "internal/runtime/maps": {mode: altPkgReplace}, + "internal/runtime/sys": {mode: altPkgAdditive}, + "iter": {mode: altPkgReplace}, + "reflect": {mode: altPkgReplace}, + "runtime": {mode: altPkgReplace}, + "sync/atomic": {mode: altPkgReplace}, + "unique": {mode: altPkgReplace}, + "syscall/js": {mode: altPkgReplace}, } diff --git a/runtime/internal/lib/internal/runtime/atomic/atomic_llgo_arm.go b/runtime/internal/lib/internal/runtime/atomic/atomic_llgo_arm.go new file mode 100644 index 0000000000..c7cf518c51 --- /dev/null +++ b/runtime/internal/lib/internal/runtime/atomic/atomic_llgo_arm.go @@ -0,0 +1,406 @@ +//go:build arm && baremetal + +package atomic + +import "unsafe" + +// This file is a single-threaded baremetal fallback for ARM targets that do not +// provide upstream runtime atomics. These helpers are plain loads/stores and do +// not provide inter-core atomicity. + +// Export some functions via linkname to assembly in sync/atomic. +// +//go:linkname Load +//go:linkname Loadp +//go:linkname Load64 +//go:linkname Loadint32 +//go:linkname Loadint64 +//go:linkname Loaduintptr +//go:linkname LoadAcq +//go:linkname LoadAcq64 +//go:linkname LoadAcquintptr +//go:linkname Load8 +//go:linkname Xadd +//go:linkname Xaddint32 +//go:linkname Xaddint64 +//go:linkname Xadd64 +//go:linkname Xadduintptr +//go:linkname Xchg +//go:linkname Xchg8 +//go:linkname Xchg64 +//go:linkname Xchgint32 +//go:linkname Xchgint64 +//go:linkname Xchguintptr +//go:linkname Cas +//go:linkname Cas64 +//go:linkname Casint32 +//go:linkname Casint64 +//go:linkname Casuintptr +//go:linkname CasRel +//go:linkname Store +//go:linkname Store8 +//go:linkname Store64 +//go:linkname Storeint32 +//go:linkname Storeint64 +//go:linkname Storeuintptr +//go:linkname StoreRel +//go:linkname StoreRel64 +//go:linkname StoreReluintptr +//go:linkname And32 +//go:linkname Or32 +//go:linkname And64 +//go:linkname Or64 +//go:linkname Anduintptr +//go:linkname Oruintptr + +//go:nosplit +//go:noinline +func Load(ptr *uint32) uint32 { + return *ptr +} + +//go:nosplit +//go:noinline +func Loadp(ptr unsafe.Pointer) unsafe.Pointer { + return *(*unsafe.Pointer)(ptr) +} + +//go:nosplit +//go:noinline +func LoadAcq(ptr *uint32) uint32 { + return *ptr +} + +//go:nosplit +//go:noinline +func LoadAcq64(ptr *uint64) uint64 { + return *ptr +} + +//go:nosplit +//go:noinline +func LoadAcquintptr(ptr *uintptr) uintptr { + return *ptr +} + +//go:nosplit +//go:noinline +func Load8(ptr *uint8) uint8 { + return *ptr +} + +//go:nosplit +//go:noinline +func Load64(ptr *uint64) uint64 { + return *ptr +} + +//go:nosplit +//go:noinline +func Xadd(ptr *uint32, delta int32) uint32 { + new := *ptr + uint32(delta) + *ptr = new + return new +} + +//go:nosplit +//go:noinline +func Xadd64(ptr *uint64, delta int64) uint64 { + new := *ptr + uint64(delta) + *ptr = new + return new +} + +//go:nosplit +//go:noinline +func Xadduintptr(ptr *uintptr, delta uintptr) uintptr { + new := *ptr + delta + *ptr = new + return new +} + +//go:nosplit +//go:noinline +func Xchg(ptr *uint32, new uint32) uint32 { + old := *ptr + *ptr = new + return old +} + +//go:nosplit +//go:noinline +func Xchg8(ptr *uint8, new uint8) uint8 { + old := *ptr + *ptr = new + return old +} + +//go:nosplit +//go:noinline +func Xchg64(ptr *uint64, new uint64) uint64 { + old := *ptr + *ptr = new + return old +} + +//go:nosplit +//go:noinline +func Xchgint32(ptr *int32, new int32) int32 { + old := *ptr + *ptr = new + return old +} + +//go:nosplit +//go:noinline +func Xchgint64(ptr *int64, new int64) int64 { + old := *ptr + *ptr = new + return old +} + +//go:nosplit +//go:noinline +func Xchguintptr(ptr *uintptr, new uintptr) uintptr { + old := *ptr + *ptr = new + return old +} + +//go:nosplit +//go:noinline +func And8(ptr *uint8, val uint8) { + *ptr = *ptr & val +} + +//go:nosplit +//go:noinline +func Or8(ptr *uint8, val uint8) { + *ptr = *ptr | val +} + +//go:nosplit +//go:noinline +func And(ptr *uint32, val uint32) { + *ptr = *ptr & val +} + +//go:nosplit +//go:noinline +func Or(ptr *uint32, val uint32) { + *ptr = *ptr | val +} + +//go:nosplit +//go:noinline +func Cas64(ptr *uint64, old, new uint64) bool { + if *ptr == old { + *ptr = new + return true + } + return false +} + +//go:nosplit +//go:noinline +func Store(ptr *uint32, val uint32) { + *ptr = val +} + +//go:nosplit +//go:noinline +func StoreRel(ptr *uint32, val uint32) { + *ptr = val +} + +//go:nosplit +//go:noinline +func StoreRel64(ptr *uint64, val uint64) { + *ptr = val +} + +//go:nosplit +//go:noinline +func StoreReluintptr(ptr *uintptr, val uintptr) { + *ptr = val +} + +//go:nosplit +//go:noinline +func Store8(ptr *uint8, val uint8) { + *ptr = val +} + +//go:nosplit +//go:noinline +func Store64(ptr *uint64, val uint64) { + *ptr = val +} + +// StorepNoWB performs *ptr = val without a write barrier. +// +//go:nosplit +//go:noinline +func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer) { + *(*unsafe.Pointer)(ptr) = val +} + +//go:nosplit +//go:noinline +func Casint32(ptr *int32, old, new int32) bool { + if *ptr == old { + *ptr = new + return true + } + return false +} + +//go:nosplit +//go:noinline +func Casint64(ptr *int64, old, new int64) bool { + if *ptr == old { + *ptr = new + return true + } + return false +} + +//go:nosplit +//go:noinline +func Cas(ptr *uint32, old, new uint32) bool { + if *ptr == old { + *ptr = new + return true + } + return false +} + +//go:nosplit +//go:noinline +func Casp1(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool { + if *ptr == old { + *ptr = new + return true + } + return false +} + +//go:nosplit +//go:noinline +func Casuintptr(ptr *uintptr, old, new uintptr) bool { + if *ptr == old { + *ptr = new + return true + } + return false +} + +//go:nosplit +//go:noinline +func CasRel(ptr *uint32, old, new uint32) bool { + if *ptr == old { + *ptr = new + return true + } + return false +} + +//go:nosplit +//go:noinline +func Storeint32(ptr *int32, new int32) { + *ptr = new +} + +//go:nosplit +//go:noinline +func Storeint64(ptr *int64, new int64) { + *ptr = new +} + +//go:nosplit +//go:noinline +func Storeuintptr(ptr *uintptr, new uintptr) { + *ptr = new +} + +//go:nosplit +//go:noinline +func Loaduintptr(ptr *uintptr) uintptr { + return *ptr +} + +//go:nosplit +//go:noinline +func Loaduint(ptr *uint) uint { + return *ptr +} + +//go:nosplit +//go:noinline +func Loadint32(ptr *int32) int32 { + return *ptr +} + +//go:nosplit +//go:noinline +func Loadint64(ptr *int64) int64 { + return *ptr +} + +//go:nosplit +//go:noinline +func Xaddint32(ptr *int32, delta int32) int32 { + new := *ptr + delta + *ptr = new + return new +} + +//go:nosplit +//go:noinline +func Xaddint64(ptr *int64, delta int64) int64 { + new := *ptr + delta + *ptr = new + return new +} + +//go:nosplit +func And32(ptr *uint32, val uint32) uint32 { + old := *ptr + *ptr = old & val + return old +} + +//go:nosplit +func Or32(ptr *uint32, val uint32) uint32 { + old := *ptr + *ptr = old | val + return old +} + +//go:nosplit +func And64(ptr *uint64, val uint64) uint64 { + old := *ptr + *ptr = old & val + return old +} + +//go:nosplit +func Or64(ptr *uint64, val uint64) uint64 { + old := *ptr + *ptr = old | val + return old +} + +//go:nosplit +func Anduintptr(ptr *uintptr, val uintptr) uintptr { + old := *ptr + *ptr = old & val + return old +} + +//go:nosplit +func Oruintptr(ptr *uintptr, val uintptr) uintptr { + old := *ptr + *ptr = old | val + return old +} diff --git a/runtime/internal/lib/internal/runtime/atomic/types_llgo_arm.go b/runtime/internal/lib/internal/runtime/atomic/types_llgo_arm.go new file mode 100644 index 0000000000..730f37c5eb --- /dev/null +++ b/runtime/internal/lib/internal/runtime/atomic/types_llgo_arm.go @@ -0,0 +1,233 @@ +//go:build arm && baremetal + +package atomic + +import "unsafe" + +type Int32 struct { + noCopy noCopy + value int32 +} + +//go:nosplit +func (i *Int32) Load() int32 { return Loadint32(&i.value) } + +//go:nosplit +func (i *Int32) Store(value int32) { Storeint32(&i.value, value) } + +//go:nosplit +func (i *Int32) CompareAndSwap(old, new int32) bool { return Casint32(&i.value, old, new) } + +//go:nosplit +func (i *Int32) Swap(new int32) int32 { return Xchgint32(&i.value, new) } + +//go:nosplit +func (i *Int32) Add(delta int32) int32 { return Xaddint32(&i.value, delta) } + +type Int64 struct { + noCopy noCopy + _ align64 + value int64 +} + +//go:nosplit +func (i *Int64) Load() int64 { return Loadint64(&i.value) } + +//go:nosplit +func (i *Int64) Store(value int64) { Storeint64(&i.value, value) } + +//go:nosplit +func (i *Int64) CompareAndSwap(old, new int64) bool { return Casint64(&i.value, old, new) } + +//go:nosplit +func (i *Int64) Swap(new int64) int64 { return Xchgint64(&i.value, new) } + +//go:nosplit +func (i *Int64) Add(delta int64) int64 { return Xaddint64(&i.value, delta) } + +type Uint8 struct { + noCopy noCopy + value uint8 +} + +//go:nosplit +func (u *Uint8) Load() uint8 { return Load8(&u.value) } + +//go:nosplit +func (u *Uint8) Store(value uint8) { Store8(&u.value, value) } + +//go:nosplit +func (u *Uint8) And(value uint8) { And8(&u.value, value) } + +//go:nosplit +func (u *Uint8) Or(value uint8) { Or8(&u.value, value) } + +type Bool struct { + u Uint8 +} + +//go:nosplit +func (b *Bool) Load() bool { return b.u.Load() != 0 } + +//go:nosplit +func (b *Bool) Store(value bool) { + s := uint8(0) + if value { + s = 1 + } + b.u.Store(s) +} + +type Uint32 struct { + noCopy noCopy + value uint32 +} + +//go:nosplit +func (u *Uint32) Load() uint32 { return Load(&u.value) } + +//go:nosplit +func (u *Uint32) LoadAcquire() uint32 { return LoadAcq(&u.value) } + +//go:nosplit +func (u *Uint32) Store(value uint32) { Store(&u.value, value) } + +//go:nosplit +func (u *Uint32) StoreRelease(value uint32) { StoreRel(&u.value, value) } + +//go:nosplit +func (u *Uint32) CompareAndSwap(old, new uint32) bool { return Cas(&u.value, old, new) } + +//go:nosplit +func (u *Uint32) CompareAndSwapRelease(old, new uint32) bool { return CasRel(&u.value, old, new) } + +//go:nosplit +func (u *Uint32) Swap(value uint32) uint32 { return Xchg(&u.value, value) } + +//go:nosplit +func (u *Uint32) And(value uint32) { And(&u.value, value) } + +//go:nosplit +func (u *Uint32) Or(value uint32) { Or(&u.value, value) } + +//go:nosplit +func (u *Uint32) Add(delta int32) uint32 { return Xadd(&u.value, delta) } + +type Uint64 struct { + noCopy noCopy + _ align64 + value uint64 +} + +//go:nosplit +func (u *Uint64) Load() uint64 { return Load64(&u.value) } + +//go:nosplit +func (u *Uint64) Store(value uint64) { Store64(&u.value, value) } + +//go:nosplit +func (u *Uint64) CompareAndSwap(old, new uint64) bool { return Cas64(&u.value, old, new) } + +//go:nosplit +func (u *Uint64) Swap(value uint64) uint64 { return Xchg64(&u.value, value) } + +//go:nosplit +func (u *Uint64) Add(delta int64) uint64 { return Xadd64(&u.value, delta) } + +type Uintptr struct { + noCopy noCopy + value uintptr +} + +//go:nosplit +func (u *Uintptr) Load() uintptr { return Loaduintptr(&u.value) } + +//go:nosplit +func (u *Uintptr) LoadAcquire() uintptr { return LoadAcquintptr(&u.value) } + +//go:nosplit +func (u *Uintptr) Store(value uintptr) { Storeuintptr(&u.value, value) } + +//go:nosplit +func (u *Uintptr) StoreRelease(value uintptr) { StoreReluintptr(&u.value, value) } + +//go:nosplit +func (u *Uintptr) CompareAndSwap(old, new uintptr) bool { return Casuintptr(&u.value, old, new) } + +//go:nosplit +func (u *Uintptr) Swap(value uintptr) uintptr { return Xchguintptr(&u.value, value) } + +//go:nosplit +func (u *Uintptr) Add(delta uintptr) uintptr { return Xadduintptr(&u.value, delta) } + +type Float64 struct { + u Uint64 +} + +//go:nosplit +func (f *Float64) Load() float64 { + r := f.u.Load() + return *(*float64)(unsafe.Pointer(&r)) +} + +//go:nosplit +func (f *Float64) Store(value float64) { + f.u.Store(*(*uint64)(unsafe.Pointer(&value))) +} + +type UnsafePointer struct { + noCopy noCopy + value unsafe.Pointer +} + +//go:nosplit +func (u *UnsafePointer) Load() unsafe.Pointer { return Loadp(unsafe.Pointer(&u.value)) } + +//go:nosplit +func (u *UnsafePointer) StoreNoWB(value unsafe.Pointer) { StorepNoWB(unsafe.Pointer(&u.value), value) } + +func (u *UnsafePointer) Store(value unsafe.Pointer) { storePointer(&u.value, value) } + +//go:linkname storePointer +func storePointer(ptr *unsafe.Pointer, new unsafe.Pointer) + +//go:nosplit +func (u *UnsafePointer) CompareAndSwapNoWB(old, new unsafe.Pointer) bool { + return Casp1(&u.value, old, new) +} + +func (u *UnsafePointer) CompareAndSwap(old, new unsafe.Pointer) bool { + return casPointer(&u.value, old, new) +} + +//go:linkname casPointer +func casPointer(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool + +type Pointer[T any] struct { + u UnsafePointer +} + +//go:nosplit +func (p *Pointer[T]) Load() *T { return (*T)(p.u.Load()) } + +//go:nosplit +func (p *Pointer[T]) StoreNoWB(value *T) { p.u.StoreNoWB(unsafe.Pointer(value)) } + +//go:nosplit +func (p *Pointer[T]) Store(value *T) { p.u.Store(unsafe.Pointer(value)) } + +//go:nosplit +func (p *Pointer[T]) CompareAndSwapNoWB(old, new *T) bool { + return p.u.CompareAndSwapNoWB(unsafe.Pointer(old), unsafe.Pointer(new)) +} + +func (p *Pointer[T]) CompareAndSwap(old, new *T) bool { + return p.u.CompareAndSwap(unsafe.Pointer(old), unsafe.Pointer(new)) +} + +type noCopy struct{} + +func (*noCopy) Lock() {} +func (*noCopy) Unlock() {} + +type align64 struct{} diff --git a/runtime/internal/lib/runtime/godebug_baremetal_llgo.go b/runtime/internal/lib/runtime/godebug_baremetal_llgo.go new file mode 100644 index 0000000000..6499496646 --- /dev/null +++ b/runtime/internal/lib/runtime/godebug_baremetal_llgo.go @@ -0,0 +1,40 @@ +//go:build baremetal + +package runtime + +import _ "unsafe" + +var ( + godebugDefault string + godebugEnv string + godebugUpdate func(string, string) +) + +func godebugGetenv() string { + return "" +} + +func godebugNotify() { + if godebugUpdate == nil { + return + } + godebugUpdate(godebugDefault, godebugEnv) +} + +func godebugEnvChanged(env string) { + godebugEnv = env + godebugNotify() +} + +//go:linkname godebug_setUpdate internal/godebug.setUpdate +func godebug_setUpdate(update func(string, string)) { + godebugUpdate = update + godebugEnv = godebugGetenv() + godebugNotify() +} + +//go:linkname godebug_setNewIncNonDefault internal/godebug.setNewIncNonDefault +func godebug_setNewIncNonDefault(newIncNonDefault func(string) func()) {} + +//go:linkname godebug_registerMetric internal/godebug.registerMetric +func godebug_registerMetric(name string, read func() uint64) {} diff --git a/runtime/internal/lib/runtime/godebug_linkname_llgo.go b/runtime/internal/lib/runtime/godebug_linkname_llgo.go index 005d798ad1..1fa205a492 100644 --- a/runtime/internal/lib/runtime/godebug_linkname_llgo.go +++ b/runtime/internal/lib/runtime/godebug_linkname_llgo.go @@ -1,3 +1,5 @@ +//go:build !baremetal + package runtime import ( diff --git a/runtime/internal/lib/runtime/link_baremetal_llgo.go b/runtime/internal/lib/runtime/link_baremetal_llgo.go new file mode 100644 index 0000000000..766f66f61c --- /dev/null +++ b/runtime/internal/lib/runtime/link_baremetal_llgo.go @@ -0,0 +1,74 @@ +//go:build baremetal + +package runtime + +import ( + _ "unsafe" + + c "github.com/goplus/llgo/runtime/internal/clite" +) + +//go:linkname os_runtime_args os.runtime_args +func os_runtime_args() []string { + return nil +} + +//go:linkname syscall_runtime_envs syscall.runtime_envs +func syscall_runtime_envs() []string { + return nil +} + +//go:linkname syscall_runtimeSetenv syscall.runtimeSetenv +func syscall_runtimeSetenv(key, value string) { + _, _ = key, value + if key == "GODEBUG" { + godebugEnvChanged(value) + } +} + +//go:linkname syscall_runtimeUnsetenv syscall.runtimeUnsetenv +func syscall_runtimeUnsetenv(key string) { + if key == "GODEBUG" { + godebugEnvChanged("") + } +} + +//go:linkname os_beforeExit os.runtime_beforeExit +func os_beforeExit(exitCode int) { + _ = exitCode +} + +//go:linkname os_sigpipe os.sigpipe +func os_sigpipe() {} + +//go:linkname os_ignoreSIGSYS os.ignoreSIGSYS +func os_ignoreSIGSYS() {} + +//go:linkname os_restoreSIGSYS os.restoreSIGSYS +func os_restoreSIGSYS() {} + +//go:linkname syscall_Getpagesize syscall.Getpagesize +func syscall_Getpagesize() int { + return 4096 +} + +//go:linkname syscall_Exit syscall.Exit +//go:nosplit +func syscall_Exit(code int) { + c.Exit(c.Int(code)) +} + +//go:linkname syscall_runtime_BeforeFork syscall.runtime_BeforeFork +func syscall_runtime_BeforeFork() {} + +//go:linkname syscall_runtime_AfterFork syscall.runtime_AfterFork +func syscall_runtime_AfterFork() {} + +//go:linkname syscall_runtime_AfterForkInChild syscall.runtime_AfterForkInChild +func syscall_runtime_AfterForkInChild() {} + +//go:linkname syscall_runtime_BeforeExec syscall.runtime_BeforeExec +func syscall_runtime_BeforeExec() {} + +//go:linkname syscall_runtime_AfterExec syscall.runtime_AfterExec +func syscall_runtime_AfterExec() {} diff --git a/runtime/internal/lib/runtime/link_linux_llgo.go b/runtime/internal/lib/runtime/link_linux_llgo.go index 577a436c03..425fef651e 100644 --- a/runtime/internal/lib/runtime/link_linux_llgo.go +++ b/runtime/internal/lib/runtime/link_linux_llgo.go @@ -1,5 +1,5 @@ -//go:build linux -// +build linux +//go:build linux && !baremetal +// +build linux,!baremetal package runtime diff --git a/runtime/internal/lib/runtime/poll_baremetal_llgo.go b/runtime/internal/lib/runtime/poll_baremetal_llgo.go new file mode 100644 index 0000000000..7dd477ca21 --- /dev/null +++ b/runtime/internal/lib/runtime/poll_baremetal_llgo.go @@ -0,0 +1,62 @@ +//go:build baremetal + +package runtime + +import _ "unsafe" + +// Minimal internal/poll hooks for baremetal target smoke builds. +// Embedded targets in this path do not provide a runtime poller. + +const ( + pollNoError = 0 + pollErrClosing = 1 + pollErrTimeout = 2 + pollErrNotPollable = 3 +) + +//go:linkname poll_runtime_pollServerInit internal/poll.runtime_pollServerInit +func poll_runtime_pollServerInit() {} + +//go:linkname poll_runtime_pollOpen internal/poll.runtime_pollOpen +func poll_runtime_pollOpen(fd uintptr) (uintptr, int) { + _ = fd + return 0, pollErrNotPollable +} + +//go:linkname poll_runtime_pollClose internal/poll.runtime_pollClose +func poll_runtime_pollClose(ctx uintptr) { + _ = ctx +} + +//go:linkname poll_runtime_pollWait internal/poll.runtime_pollWait +func poll_runtime_pollWait(ctx uintptr, mode int) int { + _, _ = ctx, mode + return pollErrNotPollable +} + +//go:linkname poll_runtime_pollWaitCanceled internal/poll.runtime_pollWaitCanceled +func poll_runtime_pollWaitCanceled(ctx uintptr, mode int) { + _, _ = ctx, mode +} + +//go:linkname poll_runtime_pollReset internal/poll.runtime_pollReset +func poll_runtime_pollReset(ctx uintptr, mode int) int { + _, _ = ctx, mode + return pollErrNotPollable +} + +//go:linkname poll_runtime_pollSetDeadline internal/poll.runtime_pollSetDeadline +func poll_runtime_pollSetDeadline(ctx uintptr, d int64, mode int) { + _, _, _ = ctx, d, mode +} + +//go:linkname poll_runtime_pollUnblock internal/poll.runtime_pollUnblock +func poll_runtime_pollUnblock(ctx uintptr) { + _ = ctx +} + +//go:linkname poll_runtime_isPollServerDescriptor internal/poll.runtime_isPollServerDescriptor +func poll_runtime_isPollServerDescriptor(fd uintptr) bool { + _ = fd + return false +} diff --git a/runtime/internal/lib/runtime/poll_linkname_llgo.go b/runtime/internal/lib/runtime/poll_linkname_llgo.go index 59d3f5ba25..47124df664 100644 --- a/runtime/internal/lib/runtime/poll_linkname_llgo.go +++ b/runtime/internal/lib/runtime/poll_linkname_llgo.go @@ -1,4 +1,4 @@ -//go:build darwin || linux +//go:build (darwin || linux) && !baremetal package runtime diff --git a/runtime/internal/lib/runtime/signal_baremetal_llgo.go b/runtime/internal/lib/runtime/signal_baremetal_llgo.go new file mode 100644 index 0000000000..a0449a5e95 --- /dev/null +++ b/runtime/internal/lib/runtime/signal_baremetal_llgo.go @@ -0,0 +1,28 @@ +//go:build baremetal + +package runtime + +// Baremetal targets do not provide OS signal delivery. + +func signal_enable(sig uint32) { + _ = sig +} + +func signal_disable(sig uint32) { + _ = sig +} + +func signal_ignore(sig uint32) { + _ = sig +} + +func signal_ignored(sig uint32) bool { + _ = sig + return false +} + +func signal_recv() uint32 { + return 0 +} + +func signalWaitUntilIdle() {} diff --git a/runtime/internal/lib/runtime/signal_llgo.go b/runtime/internal/lib/runtime/signal_llgo.go index 96ff00dd3e..7a9a2b606e 100644 --- a/runtime/internal/lib/runtime/signal_llgo.go +++ b/runtime/internal/lib/runtime/signal_llgo.go @@ -1,3 +1,5 @@ +//go:build !baremetal + package runtime import ( diff --git a/runtime/internal/lib/runtime/time_baremetal_legacy_llgo.go b/runtime/internal/lib/runtime/time_baremetal_legacy_llgo.go new file mode 100644 index 0000000000..4ef808d111 --- /dev/null +++ b/runtime/internal/lib/runtime/time_baremetal_legacy_llgo.go @@ -0,0 +1,89 @@ +//go:build baremetal && !go1.23 + +package runtime + +// Minimal timer hooks for baremetal builds. +// They keep stdlib packages linkable for target smoke tests but do not +// provide asynchronous timer delivery. + +type runtimeTimer struct { + pp uintptr + when int64 + period int64 + f func(any, uintptr) + arg any + seq uintptr + nextwhen int64 + status uint32 +} + +func startTimer(r *runtimeTimer) { + if r == nil || r.f == nil { + return + } + if r.period == 0 && r.when <= runtimeNano() { + r.f(r.arg, r.seq) + } +} + +func stopTimer(r *runtimeTimer) bool { + return r != nil +} + +func resetTimer(r *runtimeTimer, when int64) bool { + if r == nil { + return false + } + r.when = when + startTimer(r) + return true +} + +func modTimer(r *runtimeTimer, when, period int64, f func(any, uintptr), arg any, seq uintptr) { + if r == nil { + return + } + r.when = when + r.period = period + r.f = f + r.arg = arg + r.seq = seq + startTimer(r) +} + +func resetRuntimeTimer(r *runtimeTimer, when, period int64, f func(any, uintptr), arg any, seq uintptr) bool { + if r == nil { + return false + } + modTimer(r, when, period, f, arg, seq) + return true +} + +//go:linkname time_now time.now +func time_now() (sec int64, nsec int32, mono int64) { + return 0, 0, 0 +} + +//go:linkname time_runtimeNow time.runtimeNow +func time_runtimeNow() (sec int64, nsec int32, mono int64) { + return time_now() +} + +//go:linkname time_runtimeNano time.runtimeNano +func time_runtimeNano() int64 { + return runtimeNano() +} + +//go:linkname time_runtimeIsBubbled time.runtimeIsBubbled +func time_runtimeIsBubbled() bool { + return false +} + +//go:linkname timeSleep time.Sleep +func timeSleep(ns int64) { + _ = ns +} + +func runtimeNano() int64 { + return 0 +} diff --git a/runtime/internal/lib/runtime/time_baremetal_llgo.go b/runtime/internal/lib/runtime/time_baremetal_llgo.go new file mode 100644 index 0000000000..ed09ff677e --- /dev/null +++ b/runtime/internal/lib/runtime/time_baremetal_llgo.go @@ -0,0 +1,108 @@ +//go:build baremetal && go1.23 + +package runtime + +import "unsafe" + +// Minimal timer hooks for baremetal builds. +// They keep stdlib packages linkable for target smoke tests but do not +// provide asynchronous timer delivery. + +type runtimeTimer struct { + pp uintptr + when int64 + period int64 + f func(any, uintptr, int64) + arg any + seq uintptr + nextwhen int64 + status uint32 +} + +type timeTimer struct { + c unsafe.Pointer + init bool + r runtimeTimer +} + +func startRuntimeTimer(r *runtimeTimer) { + if r == nil || r.f == nil { + return + } + if r.period == 0 && r.when <= runtimeNano() { + r.f(r.arg, r.seq, runtimeNano()) + } +} + +func stopRuntimeTimer(r *runtimeTimer) bool { + return r != nil +} + +func resetRuntimeTimer(r *runtimeTimer, when, period int64, f func(any, uintptr, int64), arg any, seq uintptr) bool { + if r == nil { + return false + } + r.when = when + r.period = period + r.f = f + r.arg = arg + r.seq = seq + startRuntimeTimer(r) + return true +} + +//go:linkname time_now time.now +func time_now() (sec int64, nsec int32, mono int64) { + return 0, 0, 0 +} + +//go:linkname time_runtimeNow time.runtimeNow +func time_runtimeNow() (sec int64, nsec int32, mono int64) { + return time_now() +} + +//go:linkname time_runtimeNano time.runtimeNano +func time_runtimeNano() int64 { + return runtimeNano() +} + +//go:linkname time_runtimeIsBubbled time.runtimeIsBubbled +func time_runtimeIsBubbled() bool { + return false +} + +//go:linkname timeSleep time.Sleep +func timeSleep(ns int64) { + _ = ns +} + +//go:linkname newTimer time.newTimer +func newTimer(when, period int64, f func(any, uintptr, int64), arg any, cp unsafe.Pointer) *timeTimer { + t := &timeTimer{c: cp, init: true} + t.r.when = when + t.r.period = period + t.r.f = f + t.r.arg = arg + startRuntimeTimer(&t.r) + return t +} + +//go:linkname stopTimer time.stopTimer +func stopTimer(t *timeTimer) bool { + if t == nil { + return false + } + return stopRuntimeTimer(&t.r) +} + +//go:linkname resetTimer time.resetTimer +func resetTimer(t *timeTimer, when, period int64) bool { + if t == nil { + return false + } + return resetRuntimeTimer(&t.r, when, period, t.r.f, t.r.arg, t.r.seq) +} + +func runtimeNano() int64 { + return 0 +} diff --git a/runtime/internal/lib/runtime/time_llgo.go b/runtime/internal/lib/runtime/time_llgo.go index 061603fd62..0a09c98e07 100644 --- a/runtime/internal/lib/runtime/time_llgo.go +++ b/runtime/internal/lib/runtime/time_llgo.go @@ -1,5 +1,5 @@ -//go:build !go1.23 -// +build !go1.23 +//go:build !go1.23 && !baremetal +// +build !go1.23,!baremetal package runtime diff --git a/runtime/internal/lib/runtime/time_llgo_go123.go b/runtime/internal/lib/runtime/time_llgo_go123.go index 68022f0aa6..ceb2d73ed4 100644 --- a/runtime/internal/lib/runtime/time_llgo_go123.go +++ b/runtime/internal/lib/runtime/time_llgo_go123.go @@ -1,5 +1,5 @@ -//go:build go1.23 -// +build go1.23 +//go:build go1.23 && !baremetal +// +build go1.23,!baremetal package runtime