diff --git a/interp/errors.go b/interp/errors.go index 30007de8..4f0e4f2c 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 38001a06..e6d3be88 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 36a845d7..d5e36215 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 589c0c6f..4c66b537 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 }