mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-09-09 22:19:29 +00:00
runtime: support panic recovery on Xtensa
Use picolibc setjmp and longjmp to save and restore the complete Xtensa register-window state at TinyGo panic checkpoints. Provide the target configuration and window spill helper required by picolibc. Increment its cache version because Xtensa archives now include another source file.
This commit is contained in:
+17
-3
@@ -4,6 +4,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/tinygo-org/tinygo/compileopts"
|
||||||
"github.com/tinygo-org/tinygo/goenv"
|
"github.com/tinygo-org/tinygo/goenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -19,8 +20,9 @@ var libPicolibc = Library{
|
|||||||
return f.Close()
|
return f.Close()
|
||||||
},
|
},
|
||||||
cflags: func(target, headerPath string) []string {
|
cflags: func(target, headerPath string) []string {
|
||||||
picolibcDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc")
|
root := goenv.Get("TINYGOROOT")
|
||||||
return []string{
|
picolibcDir := filepath.Join(root, "lib/picolibc")
|
||||||
|
flags := []string{
|
||||||
"-Werror",
|
"-Werror",
|
||||||
"-Wall",
|
"-Wall",
|
||||||
"-std=gnu11",
|
"-std=gnu11",
|
||||||
@@ -39,10 +41,22 @@ var libPicolibc = Library{
|
|||||||
"-I" + picolibcDir + "/libm/common",
|
"-I" + picolibcDir + "/libm/common",
|
||||||
"-I" + headerPath,
|
"-I" + headerPath,
|
||||||
}
|
}
|
||||||
|
if compileopts.CanonicalArchName(target) == "xtensa" {
|
||||||
|
flags = append(flags,
|
||||||
|
"-I"+filepath.Join(root, "lib/xtensa/include"),
|
||||||
|
"-I"+picolibcDir+"/libc/machine/xtensa",
|
||||||
|
"-D_XTENSA_HAVE_CONFIG_CORE_ISA_H",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return flags
|
||||||
},
|
},
|
||||||
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc") },
|
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc") },
|
||||||
librarySources: func(target string, _ bool) ([]string, error) {
|
librarySources: func(target string, _ bool) ([]string, error) {
|
||||||
return append([]string(nil), picolibcSources...), nil
|
sources := append([]string(nil), picolibcSources...)
|
||||||
|
if compileopts.CanonicalArchName(target) == "xtensa" {
|
||||||
|
sources = append(sources, "libc/machine/xtensa/setjmp.S")
|
||||||
|
}
|
||||||
|
return sources, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import (
|
|||||||
var libVersions = map[string]int{
|
var libVersions = map[string]int{
|
||||||
"musl": 3,
|
"musl": 3,
|
||||||
"bdwgc": 2,
|
"bdwgc": 2,
|
||||||
"picolibc": 1,
|
"picolibc": 2,
|
||||||
"wasmbuiltins": 1,
|
"wasmbuiltins": 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-7
@@ -32,9 +32,6 @@ func (b *builder) supportsRecover() bool {
|
|||||||
// proposal of WebAssembly:
|
// proposal of WebAssembly:
|
||||||
// https://github.com/WebAssembly/exception-handling
|
// https://github.com/WebAssembly/exception-handling
|
||||||
return false
|
return false
|
||||||
case "xtensa":
|
|
||||||
// TODO: add support for these architectures
|
|
||||||
return false
|
|
||||||
default:
|
default:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -109,11 +106,21 @@ func (b *builder) createLandingPad() {
|
|||||||
b.CreateBr(b.blockInfo[b.fn.Recover.Index].entry)
|
b.CreateBr(b.blockInfo[b.fn.Recover.Index].entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a checkpoint (similar to setjmp). This emits inline assembly that
|
// Create a checkpoint (similar to setjmp). It returns whether execution is
|
||||||
// stores the current program counter inside the ptr address (actually
|
// continuing normally instead of resuming after a longjmp.
|
||||||
// ptr+sizeof(ptr)) and then returns a boolean indicating whether this is the
|
|
||||||
// normal flow (false) or we jumped here from somewhere else (true).
|
|
||||||
func (b *builder) createCheckpoint(ptr llvm.Value) llvm.Value {
|
func (b *builder) createCheckpoint(ptr llvm.Value) llvm.Value {
|
||||||
|
if b.archFamily() == "xtensa" {
|
||||||
|
fnType := llvm.FunctionType(b.ctx.Int32Type(), []llvm.Type{b.dataPtrType}, false)
|
||||||
|
fn := b.mod.NamedFunction("setjmp")
|
||||||
|
if fn.IsNil() {
|
||||||
|
fn = llvm.AddFunction(b.mod, "setjmp", fnType)
|
||||||
|
fn.AddFunctionAttr(b.ctx.CreateEnumAttribute(llvm.AttributeKindID("returns_twice"), 0))
|
||||||
|
}
|
||||||
|
result := b.CreateCall(fnType, fn, []llvm.Value{ptr}, "setjmp")
|
||||||
|
result.AddCallSiteAttribute(-1, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("returns_twice"), 0))
|
||||||
|
return b.CreateICmp(llvm.IntEQ, result, llvm.ConstInt(b.ctx.Int32Type(), 0, false), "setjmp.result")
|
||||||
|
}
|
||||||
|
|
||||||
// Construct inline assembly equivalents of setjmp.
|
// Construct inline assembly equivalents of setjmp.
|
||||||
// The assembly works as follows:
|
// The assembly works as follows:
|
||||||
// * Registers are either clobbered or, on 386, saved for longjmp to
|
// * Registers are either clobbered or, on 386, saved for longjmp to
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef TINYGO_XTENSA_CONFIG_CORE_ISA_H
|
||||||
|
#define TINYGO_XTENSA_CONFIG_CORE_ISA_H
|
||||||
|
|
||||||
|
#ifdef __XTENSA_WINDOWED_ABI__
|
||||||
|
#define XCHAL_HAVE_WINDOWED 1
|
||||||
|
#else
|
||||||
|
#define XCHAL_HAVE_WINDOWED 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __XTENSA_EB__
|
||||||
|
#define XCHAL_HAVE_BE 1
|
||||||
|
#else
|
||||||
|
#define XCHAL_HAVE_BE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define XCHAL_MAYHAVE_ERRATUM_XEA1KWIN 1
|
||||||
|
|
||||||
|
#endif
|
||||||
+13
-9
@@ -15,12 +15,14 @@ build/release: tinygo gen-device $(if $(filter 1,$(USE_SYSTEM_BINARYEN)),,binary
|
|||||||
@mkdir -p build/release/tinygo/lib/musl/src
|
@mkdir -p build/release/tinygo/lib/musl/src
|
||||||
@mkdir -p build/release/tinygo/lib/nrfx
|
@mkdir -p build/release/tinygo/lib/nrfx
|
||||||
@mkdir -p build/release/tinygo/lib/picolibc/libc
|
@mkdir -p build/release/tinygo/lib/picolibc/libc
|
||||||
|
@mkdir -p build/release/tinygo/lib/picolibc/libc/machine
|
||||||
@mkdir -p build/release/tinygo/lib/picolibc/libm
|
@mkdir -p build/release/tinygo/lib/picolibc/libm
|
||||||
@mkdir -p build/release/tinygo/lib/wasi-libc/dlmalloc
|
@mkdir -p build/release/tinygo/lib/wasi-libc/dlmalloc
|
||||||
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-bottom-half
|
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-bottom-half
|
||||||
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/arch
|
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/arch
|
||||||
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
|
@mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
|
||||||
@mkdir -p build/release/tinygo/lib/wasi-cli/
|
@mkdir -p build/release/tinygo/lib/wasi-cli/
|
||||||
|
@mkdir -p build/release/tinygo/lib/xtensa
|
||||||
@echo copying source files
|
@echo copying source files
|
||||||
@cp -p build/tinygo$(EXE) build/release/tinygo/bin
|
@cp -p build/tinygo$(EXE) build/release/tinygo/bin
|
||||||
ifneq ($(USE_SYSTEM_BINARYEN),1)
|
ifneq ($(USE_SYSTEM_BINARYEN),1)
|
||||||
@@ -80,15 +82,16 @@ endif
|
|||||||
@cp -rp lib/mingw-w64/mingw-w64-headers/defaults/include build/release/tinygo/lib/mingw-w64/mingw-w64-headers/defaults
|
@cp -rp lib/mingw-w64/mingw-w64-headers/defaults/include build/release/tinygo/lib/mingw-w64/mingw-w64-headers/defaults
|
||||||
@cp -rp lib/mingw-w64/mingw-w64-headers/include build/release/tinygo/lib/mingw-w64/mingw-w64-headers
|
@cp -rp lib/mingw-w64/mingw-w64-headers/include build/release/tinygo/lib/mingw-w64/mingw-w64-headers
|
||||||
@cp -rp lib/nrfx/* build/release/tinygo/lib/nrfx
|
@cp -rp lib/nrfx/* build/release/tinygo/lib/nrfx
|
||||||
@cp -rp lib/picolibc/libc/ctype build/release/tinygo/lib/picolibc/libc
|
@cp -rp lib/picolibc/libc/ctype build/release/tinygo/lib/picolibc/libc
|
||||||
@cp -rp lib/picolibc/libc/include build/release/tinygo/lib/picolibc/libc
|
@cp -rp lib/picolibc/libc/include build/release/tinygo/lib/picolibc/libc
|
||||||
@cp -rp lib/picolibc/libc/locale build/release/tinygo/lib/picolibc/libc
|
@cp -rp lib/picolibc/libc/locale build/release/tinygo/lib/picolibc/libc
|
||||||
@cp -rp lib/picolibc/libc/stdlib build/release/tinygo/lib/picolibc/libc
|
@cp -rp lib/picolibc/libc/machine/xtensa build/release/tinygo/lib/picolibc/libc/machine
|
||||||
@cp -rp lib/picolibc/libc/string build/release/tinygo/lib/picolibc/libc
|
@cp -rp lib/picolibc/libc/stdlib build/release/tinygo/lib/picolibc/libc
|
||||||
@cp -rp lib/picolibc/libc/stdio build/release/tinygo/lib/picolibc/libc
|
@cp -rp lib/picolibc/libc/string build/release/tinygo/lib/picolibc/libc
|
||||||
@cp -rp lib/picolibc/libm/common build/release/tinygo/lib/picolibc/libm
|
@cp -rp lib/picolibc/libc/stdio build/release/tinygo/lib/picolibc/libc
|
||||||
@cp -rp lib/picolibc/libm/math build/release/tinygo/lib/picolibc/libm
|
@cp -rp lib/picolibc/libm/common build/release/tinygo/lib/picolibc/libm
|
||||||
@cp -rp lib/picolibc-stdio.c build/release/tinygo/lib
|
@cp -rp lib/picolibc/libm/math build/release/tinygo/lib/picolibc/libm
|
||||||
|
@cp -rp lib/picolibc-stdio.c build/release/tinygo/lib
|
||||||
@cp -rp lib/wasi-libc/dlmalloc/src build/release/tinygo/lib/wasi-libc/dlmalloc
|
@cp -rp lib/wasi-libc/dlmalloc/src build/release/tinygo/lib/wasi-libc/dlmalloc
|
||||||
@cp -rp lib/wasi-libc/libc-bottom-half/cloudlibc build/release/tinygo/lib/wasi-libc/libc-bottom-half
|
@cp -rp lib/wasi-libc/libc-bottom-half/cloudlibc build/release/tinygo/lib/wasi-libc/libc-bottom-half
|
||||||
@cp -rp lib/wasi-libc/libc-bottom-half/headers build/release/tinygo/lib/wasi-libc/libc-bottom-half
|
@cp -rp lib/wasi-libc/libc-bottom-half/headers build/release/tinygo/lib/wasi-libc/libc-bottom-half
|
||||||
@@ -121,6 +124,7 @@ endif
|
|||||||
@cp -rp lib/wasi-libc/libc-top-half/musl/src/unistd build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
|
@cp -rp lib/wasi-libc/libc-top-half/musl/src/unistd build/release/tinygo/lib/wasi-libc/libc-top-half/musl/src
|
||||||
@cp -rp lib/wasi-libc/libc-top-half/sources build/release/tinygo/lib/wasi-libc/libc-top-half
|
@cp -rp lib/wasi-libc/libc-top-half/sources build/release/tinygo/lib/wasi-libc/libc-top-half
|
||||||
@cp -rp lib/wasi-cli/wit build/release/tinygo/lib/wasi-cli/wit
|
@cp -rp lib/wasi-cli/wit build/release/tinygo/lib/wasi-cli/wit
|
||||||
|
@cp -rp lib/xtensa/include build/release/tinygo/lib/xtensa
|
||||||
@cp -rp ${LLVM_PROJECTDIR}/compiler-rt/lib/builtins build/release/tinygo/lib/compiler-rt-builtins
|
@cp -rp ${LLVM_PROJECTDIR}/compiler-rt/lib/builtins build/release/tinygo/lib/compiler-rt-builtins
|
||||||
@cp -rp ${LLVM_PROJECTDIR}/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt-builtins
|
@cp -rp ${LLVM_PROJECTDIR}/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt-builtins
|
||||||
@cp -rp src build/release/tinygo/src
|
@cp -rp src build/release/tinygo/src
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ const zeroSizeAllocPtr uintptr = 16 // part of early flash: partition table, etc
|
|||||||
// The bitness of the CPU (e.g. 8, 32, 64).
|
// The bitness of the CPU (e.g. 8, 32, 64).
|
||||||
const TargetBits = 32
|
const TargetBits = 32
|
||||||
|
|
||||||
const deferExtraRegs = 0
|
// Xtensa's windowed ABI uses a 17-word jmp_buf. JumpSP and JumpPC provide the
|
||||||
|
// first two words.
|
||||||
|
const deferExtraRegs = 15
|
||||||
|
|
||||||
const callInstSize = 3 // "callx0 someFunction" (and similar) is 3 bytes
|
const callInstSize = 3 // "callx0 someFunction" (and similar) is 3 bytes
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#ifdef __XTENSA_WINDOWED_ABI__
|
||||||
|
.section .text.__xtensa_libgcc_window_spill,"ax",@progbits
|
||||||
|
.global __xtensa_libgcc_window_spill
|
||||||
|
.type __xtensa_libgcc_window_spill, %function
|
||||||
|
__xtensa_libgcc_window_spill:
|
||||||
|
entry sp, 16
|
||||||
|
movi a6, 15
|
||||||
|
call4 .Lspill_windows
|
||||||
|
retw
|
||||||
|
.size __xtensa_libgcc_window_spill, .-__xtensa_libgcc_window_spill
|
||||||
|
|
||||||
|
.balign 4
|
||||||
|
.Lspill_windows:
|
||||||
|
entry sp, 16
|
||||||
|
beqz a2, .Lspill_done
|
||||||
|
addi a2, a2, -1
|
||||||
|
mov a6, a2
|
||||||
|
call4 .Lspill_windows
|
||||||
|
.Lspill_done:
|
||||||
|
retw
|
||||||
|
#endif
|
||||||
|
|
||||||
|
.section .text.tinygo_longjmp,"ax",@progbits
|
||||||
|
.global tinygo_longjmp
|
||||||
|
.type tinygo_longjmp, %function
|
||||||
|
tinygo_longjmp:
|
||||||
|
#ifdef __XTENSA_WINDOWED_ABI__
|
||||||
|
// longjmp's entry rotates a10/a11 into its a2/a3 arguments.
|
||||||
|
movi a11, 1
|
||||||
|
#else
|
||||||
|
movi a3, 1
|
||||||
|
#endif
|
||||||
|
j longjmp
|
||||||
|
.size tinygo_longjmp, .-tinygo_longjmp
|
||||||
+2
-1
@@ -14,5 +14,6 @@
|
|||||||
],
|
],
|
||||||
"ldflags": [
|
"ldflags": [
|
||||||
"--gc-sections"
|
"--gc-sections"
|
||||||
]
|
],
|
||||||
|
"extra-files": ["src/runtime/asm_xtensa.S"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user