Skip to content

Commit 0e11a73

Browse files
authored
Merge branch 'dev' into i2c-rp2040
2 parents 586c6fb + 98e70c9 commit 0e11a73

27 files changed

+727
-84
lines changed

builder/build.go

+60-25
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
100100
AutomaticStackSize: config.AutomaticStackSize(),
101101
DefaultStackSize: config.Target.DefaultStackSize,
102102
NeedsStackObjects: config.NeedsStackObjects(),
103-
Debug: config.Debug(),
103+
Debug: true,
104104
LLVMFeatures: config.LLVMFeatures(),
105105
}
106106

@@ -470,33 +470,10 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
470470
linkerDependencies = append(linkerDependencies, job)
471471
}
472472

473-
// Add libc dependency if needed.
474-
root := goenv.Get("TINYGOROOT")
475-
switch config.Target.Libc {
476-
case "picolibc":
477-
job, err := Picolibc.load(config.Triple(), config.CPU(), dir)
478-
if err != nil {
479-
return err
480-
}
481-
// The library needs to be compiled (cache miss).
482-
jobs = append(jobs, job.dependencies...)
483-
jobs = append(jobs, job)
484-
linkerDependencies = append(linkerDependencies, job)
485-
case "wasi-libc":
486-
path := filepath.Join(root, "lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a")
487-
if _, err := os.Stat(path); os.IsNotExist(err) {
488-
return errors.New("could not find wasi-libc, perhaps you need to run `make wasi-libc`?")
489-
}
490-
ldflags = append(ldflags, path)
491-
case "":
492-
// no library specified, so nothing to do
493-
default:
494-
return fmt.Errorf("unknown libc: %s", config.Target.Libc)
495-
}
496-
497473
// Add jobs to compile extra files. These files are in C or assembly and
498474
// contain things like the interrupt vector table and low level operations
499475
// such as stack switching.
476+
root := goenv.Get("TINYGOROOT")
500477
for _, path := range config.ExtraFiles() {
501478
abspath := filepath.Join(root, path)
502479
job := &compileJob{
@@ -537,6 +514,64 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
537514
ldflags = append(ldflags, lprogram.LDFlags...)
538515
}
539516

517+
// Add libc dependency if needed.
518+
switch config.Target.Libc {
519+
case "picolibc":
520+
job, err := Picolibc.load(config.Triple(), config.CPU(), dir)
521+
if err != nil {
522+
return err
523+
}
524+
// The library needs to be compiled (cache miss).
525+
jobs = append(jobs, job.dependencies...)
526+
jobs = append(jobs, job)
527+
linkerDependencies = append(linkerDependencies, job)
528+
case "wasi-libc":
529+
path := filepath.Join(root, "lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a")
530+
if _, err := os.Stat(path); os.IsNotExist(err) {
531+
return errors.New("could not find wasi-libc, perhaps you need to run `make wasi-libc`?")
532+
}
533+
job := dummyCompileJob(path)
534+
jobs = append(jobs, job)
535+
linkerDependencies = append(linkerDependencies, job)
536+
case "":
537+
// no library specified, so nothing to do
538+
default:
539+
return fmt.Errorf("unknown libc: %s", config.Target.Libc)
540+
}
541+
542+
// Strip debug information with -no-debug.
543+
if !config.Debug() {
544+
for _, tag := range config.BuildTags() {
545+
if tag == "baremetal" {
546+
// Don't use -no-debug on baremetal targets. It makes no sense:
547+
// the debug information isn't flashed to the device anyway.
548+
return fmt.Errorf("stripping debug information is unnecessary for baremetal targets")
549+
}
550+
}
551+
if config.Target.Linker == "wasm-ld" {
552+
// Don't just strip debug information, also compress relocations
553+
// while we're at it. Relocations can only be compressed when debug
554+
// information is stripped.
555+
ldflags = append(ldflags, "--strip-debug", "--compress-relocations")
556+
} else {
557+
switch config.GOOS() {
558+
case "linux":
559+
// Either real linux or an embedded system (like AVR) that
560+
// pretends to be Linux. It's a ELF linker wrapped by GCC in any
561+
// case.
562+
ldflags = append(ldflags, "-Wl,--strip-debug")
563+
case "darwin":
564+
// MacOS (darwin) doesn't have a linker flag to strip debug
565+
// information. Apple expects you to use the strip command
566+
// instead.
567+
return errors.New("cannot remove debug information: MacOS doesn't suppor this linker flag")
568+
default:
569+
// Other OSes may have different flags.
570+
return errors.New("cannot remove debug information: unknown OS: " + config.GOOS())
571+
}
572+
}
573+
}
574+
540575
// Create a linker job, which links all object files together and does some
541576
// extra stuff that can only be done after linking.
542577
jobs = append(jobs, &compileJob{

compileopts/config.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func (c *Config) GOARCH() string {
5555

5656
// BuildTags returns the complete list of build tags used during this build.
5757
func (c *Config) BuildTags() []string {
58-
tags := append(c.Target.BuildTags, []string{"tinygo", "gc." + c.GC(), "scheduler." + c.Scheduler(), "serial." + c.Serial()}...)
58+
tags := append(c.Target.BuildTags, []string{"tinygo", "math_big_pure_go", "gc." + c.GC(), "scheduler." + c.Scheduler(), "serial." + c.Serial()}...)
5959
for i := 1; i <= c.GoMinorVersion; i++ {
6060
tags = append(tags, fmt.Sprintf("go1.%d", i))
6161
}
@@ -209,9 +209,8 @@ func (c *Config) CFlags() []string {
209209
cflags = append(cflags, "-nostdlibinc", "-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "picolibc", "newlib", "libc", "include"))
210210
cflags = append(cflags, "-I"+filepath.Join(root, "lib/picolibc-include"))
211211
}
212-
if c.Debug() {
213-
cflags = append(cflags, "-g")
214-
}
212+
// Always emit debug information. It is optionally stripped at link time.
213+
cflags = append(cflags, "-g")
215214
return cflags
216215
}
217216

@@ -250,8 +249,9 @@ func (c *Config) VerifyIR() bool {
250249
return c.Options.VerifyIR
251250
}
252251

253-
// Debug returns whether to add debug symbols to the IR, for debugging with GDB
254-
// and similar.
252+
// Debug returns whether debug (DWARF) information should be retained by the
253+
// linker. By default, debug information is retained but it can be removed with
254+
// the -no-debug flag.
255255
func (c *Config) Debug() bool {
256256
return c.Options.Debug
257257
}

interp/errors.go

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ func (r *runner) errorAt(inst instruction, err error) *Error {
5757
pos := getPosition(inst.llvmInst)
5858
return &Error{
5959
ImportPath: r.pkgName,
60+
Inst: inst.llvmInst,
6061
Pos: pos,
6162
Err: err,
6263
Traceback: []ErrorLine{{pos, inst.llvmInst}},

interp/interp.go

+27-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
// package is changed in a way that affects the output so that cached package
1616
// builds will be invalidated.
1717
// This version is independent of the TinyGo version number.
18-
const Version = 1
18+
const Version = 2 // last change: fix GEP on untyped pointers
1919

2020
// Enable extra checks, which should be disabled by default.
2121
// This may help track down bugs by adding a few more sanity checks.
@@ -110,17 +110,26 @@ func Run(mod llvm.Module, debug bool) error {
110110
fmt.Fprintln(os.Stderr, "call:", fn.Name())
111111
}
112112
_, mem, callErr := r.run(r.getFunction(fn), nil, nil, " ")
113+
call.EraseFromParentAsInstruction()
113114
if callErr != nil {
114115
if isRecoverableError(callErr.Err) {
115116
if r.debug {
116117
fmt.Fprintln(os.Stderr, "not interpreting", r.pkgName, "because of error:", callErr.Error())
117118
}
119+
// Remove instructions that were created as part of interpreting
120+
// the package.
118121
mem.revert()
122+
// Create a call to the package initializer (which was
123+
// previously deleted).
124+
i8undef := llvm.Undef(r.i8ptrType)
125+
r.builder.CreateCall(fn, []llvm.Value{i8undef, i8undef}, "")
126+
// Make sure that any globals touched by the package
127+
// initializer, won't be accessed by later package initializers.
128+
r.markExternalLoad(fn)
119129
continue
120130
}
121131
return callErr
122132
}
123-
call.EraseFromParentAsInstruction()
124133
for index, obj := range mem.objects {
125134
r.objects[index] = obj
126135
}
@@ -270,3 +279,19 @@ func (r *runner) getFunction(llvmFn llvm.Value) *function {
270279
r.functionCache[llvmFn] = fn
271280
return fn
272281
}
282+
283+
// markExternalLoad marks the given llvmValue as being loaded externally. This
284+
// is primarily used to mark package initializers that could not be run at
285+
// compile time. As an example, a package initialize might store to a global
286+
// variable. Another package initializer might read from the same global
287+
// variable. By marking this function as being run at runtime, that load
288+
// instruction will need to be run at runtime instead of at compile time.
289+
func (r *runner) markExternalLoad(llvmValue llvm.Value) {
290+
mem := memoryView{r: r}
291+
mem.markExternalLoad(llvmValue)
292+
for index, obj := range mem.objects {
293+
if obj.marked > r.objects[index].marked {
294+
r.objects[index].marked = obj.marked
295+
}
296+
}
297+
}

interp/interp_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ func TestInterp(t *testing.T) {
1717
"slice-copy",
1818
"consteval",
1919
"interface",
20+
"revert",
2021
} {
2122
name := name // make tc local to this closure
2223
t.Run(name, func(t *testing.T) {

interp/memory.go

+11
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,17 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Val
572572
}
573573

574574
if llvmType.IsNil() {
575+
if v.offset() != 0 {
576+
// If there is an offset, make sure to use a GEP to index into the
577+
// pointer. Because there is no expected type, we use whatever is
578+
// most convenient: an *i8 type. It is trivial to index byte-wise.
579+
if llvmValue.Type() != mem.r.i8ptrType {
580+
llvmValue = llvm.ConstBitCast(llvmValue, mem.r.i8ptrType)
581+
}
582+
llvmValue = llvm.ConstInBoundsGEP(llvmValue, []llvm.Value{
583+
llvm.ConstInt(llvmValue.Type().Context().Int32Type(), uint64(v.offset()), false),
584+
})
585+
}
575586
return llvmValue, nil
576587
}
577588

interp/testdata/revert.ll

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
2+
target triple = "x86_64--linux"
3+
4+
declare void @externalCall(i64)
5+
6+
@foo.knownAtRuntime = global i64 0
7+
@bar.knownAtRuntime = global i64 0
8+
9+
define void @runtime.initAll() unnamed_addr {
10+
entry:
11+
call void @foo.init(i8* undef, i8* undef)
12+
call void @bar.init(i8* undef, i8* undef)
13+
call void @main.init(i8* undef, i8* undef)
14+
ret void
15+
}
16+
17+
define internal void @foo.init(i8* %context, i8* %parentHandle) unnamed_addr {
18+
store i64 5, i64* @foo.knownAtRuntime
19+
unreachable ; this triggers a revert of @foo.init.
20+
}
21+
22+
define internal void @bar.init(i8* %context, i8* %parentHandle) unnamed_addr {
23+
%val = load i64, i64* @foo.knownAtRuntime
24+
store i64 %val, i64* @bar.knownAtRuntime
25+
ret void
26+
}
27+
28+
define internal void @main.init(i8* %context, i8* %parentHandle) unnamed_addr {
29+
entry:
30+
call void @externalCall(i64 3)
31+
ret void
32+
}

interp/testdata/revert.out.ll

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
2+
target triple = "x86_64--linux"
3+
4+
@foo.knownAtRuntime = local_unnamed_addr global i64 0
5+
@bar.knownAtRuntime = local_unnamed_addr global i64 0
6+
7+
declare void @externalCall(i64) local_unnamed_addr
8+
9+
define void @runtime.initAll() unnamed_addr {
10+
entry:
11+
call fastcc void @foo.init(i8* undef, i8* undef)
12+
%val = load i64, i64* @foo.knownAtRuntime, align 8
13+
store i64 %val, i64* @bar.knownAtRuntime, align 8
14+
call void @externalCall(i64 3)
15+
ret void
16+
}
17+
18+
define internal fastcc void @foo.init(i8* %context, i8* %parentHandle) unnamed_addr {
19+
store i64 5, i64* @foo.knownAtRuntime, align 8
20+
unreachable
21+
}

main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,7 @@ func main() {
10191019
printStacks := flag.Bool("print-stacks", false, "print stack sizes of goroutines")
10201020
printAllocsString := flag.String("print-allocs", "", "regular expression of functions for which heap allocations should be printed")
10211021
printCommands := flag.Bool("x", false, "Print commands")
1022-
nodebug := flag.Bool("no-debug", false, "disable DWARF debug symbol generation")
1022+
nodebug := flag.Bool("no-debug", false, "strip debug information")
10231023
ocdCommandsString := flag.String("ocd-commands", "", "OpenOCD commands, overriding target spec (can specify multiple separated by commas)")
10241024
ocdOutput := flag.Bool("ocd-output", false, "print OCD daemon output during debug")
10251025
port := flag.String("port", "", "flash port (can specify multiple candidates separated by commas)")

main_test.go

+14-15
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ func TestCompiler(t *testing.T) {
125125
// Test with few optimizations enabled (no inlining, etc).
126126
t.Run("opt=1", func(t *testing.T) {
127127
t.Parallel()
128-
runTestWithConfig("stdlib.go", "", t, &compileopts.Options{
128+
runTestWithConfig("stdlib.go", "", t, compileopts.Options{
129129
Opt: "1",
130130
}, nil, nil)
131131
})
@@ -134,15 +134,14 @@ func TestCompiler(t *testing.T) {
134134
// TODO: fix this for stdlib.go, which currently fails.
135135
t.Run("opt=0", func(t *testing.T) {
136136
t.Parallel()
137-
runTestWithConfig("print.go", "", t, &compileopts.Options{
137+
runTestWithConfig("print.go", "", t, compileopts.Options{
138138
Opt: "0",
139139
}, nil, nil)
140140
})
141141

142142
t.Run("ldflags", func(t *testing.T) {
143143
t.Parallel()
144-
runTestWithConfig("ldflags.go", "", t, &compileopts.Options{
145-
Opt: "z",
144+
runTestWithConfig("ldflags.go", "", t, compileopts.Options{
146145
GlobalValues: map[string]map[string]string{
147146
"main": {
148147
"someGlobal": "foobar",
@@ -188,20 +187,20 @@ func runBuild(src, out string, opts *compileopts.Options) error {
188187
}
189188

190189
func runTest(name, target string, t *testing.T, cmdArgs, environmentVars []string) {
191-
options := &compileopts.Options{
192-
Target: target,
193-
Opt: "z",
194-
PrintIR: false,
195-
DumpSSA: false,
196-
VerifyIR: true,
197-
Debug: true,
198-
PrintSizes: "",
199-
WasmAbi: "",
190+
options := compileopts.Options{
191+
Target: target,
200192
}
201193
runTestWithConfig(name, target, t, options, cmdArgs, environmentVars)
202194
}
203195

204-
func runTestWithConfig(name, target string, t *testing.T, options *compileopts.Options, cmdArgs, environmentVars []string) {
196+
func runTestWithConfig(name, target string, t *testing.T, options compileopts.Options, cmdArgs, environmentVars []string) {
197+
// Set default config.
198+
options.Debug = true
199+
options.VerifyIR = true
200+
if options.Opt == "" {
201+
options.Opt = "z"
202+
}
203+
205204
// Get the expected output for this test.
206205
// Note: not using filepath.Join as it strips the path separator at the end
207206
// of the path.
@@ -230,7 +229,7 @@ func runTestWithConfig(name, target string, t *testing.T, options *compileopts.O
230229

231230
// Build the test binary.
232231
binary := filepath.Join(tmpdir, "test")
233-
err = runBuild("./"+path, binary, options)
232+
err = runBuild("./"+path, binary, &options)
234233
if err != nil {
235234
printCompilerError(t.Log, err)
236235
t.Fail()

src/machine/board_feather-nrf52840-sense.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ const (
7272

7373
// UART0 pins (logical UART1)
7474
const (
75-
UART_RX_PIN = D0
76-
UART_TX_PIN = D1
75+
UART_RX_PIN = D1
76+
UART_TX_PIN = D0
7777
)
7878

7979
// I2C pins
@@ -99,3 +99,7 @@ var (
9999
usb_VID uint16 = 0x239A
100100
usb_PID uint16 = 0x8088
101101
)
102+
103+
var (
104+
DefaultUART = UART0
105+
)

0 commit comments

Comments
 (0)