From f50758ca5ab29c98fd39b9efccff0aec3d739903 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Mon, 22 Feb 2021 20:49:02 +0100 Subject: [PATCH] interp: support GEP on fixed (MMIO) addresses GetElementPtr would not work on values that weren't pointers. Because fixed addresses (often used in memory-mapped I/O) are integers rather than pointers in interp, it would return an error. This resulted in the teensy40 target not compiling correctly since the interp package rewrite. This commit should fix that. --- interp/errors.go | 6 ++---- interp/interp.go | 2 +- interp/interpreter.go | 17 ++++++++++++++++- interp/memory.go | 4 ++-- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/interp/errors.go b/interp/errors.go index 30007de84..4f0e4f2c5 100644 --- a/interp/errors.go +++ b/interp/errors.go @@ -11,19 +11,17 @@ import ( "tinygo.org/x/go-llvm" ) -var errLiteralToPointer = errors.New("interp: trying to convert literal value to pointer") - // These errors are expected during normal execution and can be recovered from // by running the affected function at runtime instead of compile time. var ( - errExpectedPointer = errors.New("interp: trying to use an integer as a pointer (memory-mapped I/O?)") + errIntegerAsPointer = errors.New("interp: trying to use an integer as a pointer (memory-mapped I/O?)") errUnsupportedInst = errors.New("interp: unsupported instruction") errUnsupportedRuntimeInst = errors.New("interp: unsupported instruction (to be emitted at runtime)") errMapAlreadyCreated = errors.New("interp: map already created") ) func isRecoverableError(err error) bool { - return err == errExpectedPointer || err == errUnsupportedInst || err == errUnsupportedRuntimeInst || err == errMapAlreadyCreated + return err == errIntegerAsPointer || err == errUnsupportedInst || err == errUnsupportedRuntimeInst || err == errMapAlreadyCreated } // ErrorLine is one line in a traceback. The position may be missing. diff --git a/interp/interp.go b/interp/interp.go index 38001a069..e6d3be88d 100644 --- a/interp/interp.go +++ b/interp/interp.go @@ -102,7 +102,7 @@ func Run(mod llvm.Module, debug bool) error { if callErr != nil { if isRecoverableError(callErr.Err) { if r.debug { - fmt.Fprintln(os.Stderr, "not interpretring", r.pkgName, "because of error:", callErr.Err) + fmt.Fprintln(os.Stderr, "not interpreting", r.pkgName, "because of error:", callErr.Error()) } mem.revert() continue diff --git a/interp/interpreter.go b/interp/interpreter.go index 36a845d7c..d5e36215a 100644 --- a/interp/interpreter.go +++ b/interp/interpreter.go @@ -550,7 +550,22 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent } ptr, err := operands[0].asPointer(r) if err != nil { - return nil, mem, r.errorAt(inst, err) + if err != errIntegerAsPointer { + return nil, mem, r.errorAt(inst, err) + } + // GEP on fixed pointer value (for example, memory-mapped I/O). + ptrValue := operands[0].Uint() + offset + switch operands[0].len(r) { + case 8: + locals[inst.localIndex] = literalValue{uint64(ptrValue)} + case 4: + locals[inst.localIndex] = literalValue{uint32(ptrValue)} + case 2: + locals[inst.localIndex] = literalValue{uint16(ptrValue)} + default: + panic("pointer operand is not of a known pointer size") + } + continue } ptr = ptr.addOffset(uint32(offset)) locals[inst.localIndex] = ptr diff --git a/interp/memory.go b/interp/memory.go index 589c0c6f7..4c66b5378 100644 --- a/interp/memory.go +++ b/interp/memory.go @@ -348,7 +348,7 @@ func (v literalValue) clone() value { } func (v literalValue) asPointer(r *runner) (pointerValue, error) { - return pointerValue{}, errLiteralToPointer + return pointerValue{}, errIntegerAsPointer } func (v literalValue) asRawValue(r *runner) rawValue { @@ -949,7 +949,7 @@ func (v rawValue) clone() value { func (v rawValue) asPointer(r *runner) (pointerValue, error) { if v.buf[0] <= 255 { // Probably a null pointer or memory-mapped I/O. - return pointerValue{}, errExpectedPointer + return pointerValue{}, errIntegerAsPointer } return pointerValue{v.buf[0]}, nil }