mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 06:38:42 +00:00
dfbb133ea6
This switches the Espressif fork from LLVM 19 to LLVM 20, so we can use the improvements made between those LLVM versions. It also better aligns with the system-LLVM build method, which currently also defaults to LLVM 20. Note that this disables the machine outliner for RISC-V. It appears there's a bug in there somewhere, with the machine outliner enabled the crypto/elliptic package tests fail with -target=riscv-qemu. This should ideally be investigated and reported upstream.
141 lines
4.2 KiB
Go
141 lines
4.2 KiB
Go
package builder
|
|
|
|
import (
|
|
"regexp"
|
|
"runtime"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/tinygo-org/tinygo/compileopts"
|
|
)
|
|
|
|
var sema = make(chan struct{}, runtime.NumCPU())
|
|
|
|
type sizeTest struct {
|
|
target string
|
|
path string
|
|
codeSize uint64
|
|
rodataSize uint64
|
|
dataSize uint64
|
|
bssSize uint64
|
|
}
|
|
|
|
// Test whether code and data size is as expected for the given targets.
|
|
// This tests both the logic of loadProgramSize and checks that code size
|
|
// doesn't change unintentionally.
|
|
//
|
|
// If you find that code or data size is reduced, then great! You can reduce the
|
|
// number in this test.
|
|
// If you find that the code or data size is increased, take a look as to why
|
|
// this is. It could be due to an update (LLVM version, Go version, etc) which
|
|
// is fine, but it could also mean that a recent change introduced this size
|
|
// increase. If so, please consider whether this new feature is indeed worth the
|
|
// size increase for all users.
|
|
func TestBinarySize(t *testing.T) {
|
|
if runtime.GOOS == "linux" && !hasBuiltinTools {
|
|
// Debian LLVM packages are modified a bit and tend to produce
|
|
// different machine code. Ideally we'd fix this (with some attributes
|
|
// or something?), but for now skip it.
|
|
t.Skip("Skip: using external LLVM version so binary size might differ")
|
|
}
|
|
|
|
// This is a small number of very diverse targets that we want to test.
|
|
tests := []sizeTest{
|
|
// microcontrollers
|
|
{"hifive1b", "examples/echo", 3884, 280, 0, 2268},
|
|
{"microbit", "examples/serial", 2924, 388, 8, 2272},
|
|
{"wioterminal", "examples/pininterrupt", 7365, 1491, 116, 6912},
|
|
|
|
// TODO: also check wasm. Right now this is difficult, because
|
|
// wasm binaries are run through wasm-opt and therefore the
|
|
// output varies by binaryen version.
|
|
}
|
|
for _, tc := range tests {
|
|
tc := tc
|
|
t.Run(tc.target+"/"+tc.path, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Build the binary.
|
|
result := buildBinary(t, tc.target, tc.path)
|
|
|
|
// Check whether the size of the binary matches the expected size.
|
|
sizes, err := loadProgramSize(result.Executable, nil)
|
|
if err != nil {
|
|
t.Fatal("could not read program size:", err)
|
|
}
|
|
if sizes.Code != tc.codeSize || sizes.ROData != tc.rodataSize || sizes.Data != tc.dataSize || sizes.BSS != tc.bssSize {
|
|
t.Errorf("Unexpected code size when compiling: -target=%s %s", tc.target, tc.path)
|
|
t.Errorf(" code rodata data bss")
|
|
t.Errorf("expected: %6d %6d %6d %6d", tc.codeSize, tc.rodataSize, tc.dataSize, tc.bssSize)
|
|
t.Errorf("actual: %6d %6d %6d %6d", sizes.Code, sizes.ROData, sizes.Data, sizes.BSS)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// Check that the -size=full flag attributes binary size to the correct package
|
|
// without filesystem paths and things like that.
|
|
func TestSizeFull(t *testing.T) {
|
|
tests := []string{
|
|
"microbit",
|
|
"wasip1",
|
|
}
|
|
|
|
libMatch := regexp.MustCompile(`^C [a-z -]+$`) // example: "C interrupt vector"
|
|
pkgMatch := regexp.MustCompile(`^[a-z/]+$`) // example: "internal/task"
|
|
|
|
for _, target := range tests {
|
|
target := target
|
|
t.Run(target, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Build the binary.
|
|
result := buildBinary(t, target, "examples/serial")
|
|
|
|
// Check whether the binary doesn't contain any unexpected package
|
|
// names.
|
|
sizes, err := loadProgramSize(result.Executable, result.PackagePathMap)
|
|
if err != nil {
|
|
t.Fatal("could not read program size:", err)
|
|
}
|
|
for _, pkg := range sizes.sortedPackageNames() {
|
|
if pkg == "(padding)" || pkg == "(unknown)" {
|
|
// TODO: correctly attribute all unknown binary size.
|
|
continue
|
|
}
|
|
if libMatch.MatchString(pkg) {
|
|
continue
|
|
}
|
|
if pkgMatch.MatchString(pkg) {
|
|
continue
|
|
}
|
|
t.Error("unexpected package name in size output:", pkg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func buildBinary(t *testing.T, targetString, pkgName string) BuildResult {
|
|
options := compileopts.Options{
|
|
Target: targetString,
|
|
Opt: "z",
|
|
Semaphore: sema,
|
|
InterpTimeout: 60 * time.Second,
|
|
Debug: true,
|
|
VerifyIR: true,
|
|
}
|
|
target, err := compileopts.LoadTarget(&options)
|
|
if err != nil {
|
|
t.Fatal("could not load target:", err)
|
|
}
|
|
config := &compileopts.Config{
|
|
Options: &options,
|
|
Target: target,
|
|
}
|
|
result, err := Build(pkgName, "", t.TempDir(), config)
|
|
if err != nil {
|
|
t.Fatal("could not build:", err)
|
|
}
|
|
return result
|
|
}
|