mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-20 12:29:03 +00:00
interp: support big-endian targets
The interp package was assuming that all targets were little-endian. But that's not true: we now have a big-endian target (GOARCH=mips). This fixes the interp package to use the appropriate byte order for a given target.
This commit is contained in:
committed by
Ron Evans
parent
25abfff632
commit
73f519b589
@@ -8,6 +8,7 @@
|
|||||||
package llvmutil
|
package llvmutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -216,3 +217,13 @@ func Version() int {
|
|||||||
}
|
}
|
||||||
return major
|
return major
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the byte order for the given target triple. Most targets are little
|
||||||
|
// endian, but for example MIPS can be big-endian.
|
||||||
|
func ByteOrder(target string) binary.ByteOrder {
|
||||||
|
if strings.HasPrefix(target, "mips-") {
|
||||||
|
return binary.BigEndian
|
||||||
|
} else {
|
||||||
|
return binary.LittleEndian
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,11 +3,13 @@
|
|||||||
package interp
|
package interp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/tinygo-org/tinygo/compiler/llvmutil"
|
||||||
"tinygo.org/x/go-llvm"
|
"tinygo.org/x/go-llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -24,6 +26,7 @@ type runner struct {
|
|||||||
dataPtrType llvm.Type // often used type so created in advance
|
dataPtrType llvm.Type // often used type so created in advance
|
||||||
uintptrType llvm.Type // equivalent to uintptr in Go
|
uintptrType llvm.Type // equivalent to uintptr in Go
|
||||||
maxAlign int // maximum alignment of an object, alignment of runtime.alloc() result
|
maxAlign int // maximum alignment of an object, alignment of runtime.alloc() result
|
||||||
|
byteOrder binary.ByteOrder // big-endian or little-endian
|
||||||
debug bool // log debug messages
|
debug bool // log debug messages
|
||||||
pkgName string // package name of the currently executing package
|
pkgName string // package name of the currently executing package
|
||||||
functionCache map[llvm.Value]*function // cache of compiled functions
|
functionCache map[llvm.Value]*function // cache of compiled functions
|
||||||
@@ -38,6 +41,7 @@ func newRunner(mod llvm.Module, timeout time.Duration, debug bool) *runner {
|
|||||||
r := runner{
|
r := runner{
|
||||||
mod: mod,
|
mod: mod,
|
||||||
targetData: llvm.NewTargetData(mod.DataLayout()),
|
targetData: llvm.NewTargetData(mod.DataLayout()),
|
||||||
|
byteOrder: llvmutil.ByteOrder(mod.Target()),
|
||||||
debug: debug,
|
debug: debug,
|
||||||
functionCache: make(map[llvm.Value]*function),
|
functionCache: make(map[llvm.Value]*function),
|
||||||
objects: []object{{}},
|
objects: []object{{}},
|
||||||
|
|||||||
+49
-49
@@ -173,7 +173,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
case 3:
|
case 3:
|
||||||
// Conditional branch: [cond, thenBB, elseBB]
|
// Conditional branch: [cond, thenBB, elseBB]
|
||||||
lastBB = currentBB
|
lastBB = currentBB
|
||||||
switch operands[0].Uint() {
|
switch operands[0].Uint(r) {
|
||||||
case 1: // true -> thenBB
|
case 1: // true -> thenBB
|
||||||
currentBB = int(operands[1].(literalValue).value.(uint32))
|
currentBB = int(operands[1].(literalValue).value.(uint32))
|
||||||
case 0: // false -> elseBB
|
case 0: // false -> elseBB
|
||||||
@@ -191,12 +191,12 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
}
|
}
|
||||||
case llvm.Switch:
|
case llvm.Switch:
|
||||||
// Switch statement: [value, defaultLabel, case0, label0, case1, label1, ...]
|
// Switch statement: [value, defaultLabel, case0, label0, case1, label1, ...]
|
||||||
value := operands[0].Uint()
|
value := operands[0].Uint(r)
|
||||||
targetLabel := operands[1].Uint() // default label
|
targetLabel := operands[1].Uint(r) // default label
|
||||||
// Do a lazy switch by iterating over all cases.
|
// Do a lazy switch by iterating over all cases.
|
||||||
for i := 2; i < len(operands); i += 2 {
|
for i := 2; i < len(operands); i += 2 {
|
||||||
if value == operands[i].Uint() {
|
if value == operands[i].Uint(r) {
|
||||||
targetLabel = operands[i+1].Uint()
|
targetLabel = operands[i+1].Uint(r)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -211,7 +211,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
// Select is much like a ternary operator: it picks a result from
|
// Select is much like a ternary operator: it picks a result from
|
||||||
// the second and third operand based on the boolean first operand.
|
// the second and third operand based on the boolean first operand.
|
||||||
var result value
|
var result value
|
||||||
switch operands[0].Uint() {
|
switch operands[0].Uint(r) {
|
||||||
case 1:
|
case 1:
|
||||||
result = operands[1]
|
result = operands[1]
|
||||||
case 0:
|
case 0:
|
||||||
@@ -282,7 +282,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
// by creating a global variable.
|
// by creating a global variable.
|
||||||
|
|
||||||
// Get the requested memory size to be allocated.
|
// Get the requested memory size to be allocated.
|
||||||
size := operands[1].Uint()
|
size := operands[1].Uint(r)
|
||||||
|
|
||||||
// Get the object layout, if it is available.
|
// Get the object layout, if it is available.
|
||||||
llvmLayoutType := r.getLLVMTypeFromLayout(operands[2])
|
llvmLayoutType := r.getLLVMTypeFromLayout(operands[2])
|
||||||
@@ -318,9 +318,9 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
// memmove(dst, src, n*elemSize)
|
// memmove(dst, src, n*elemSize)
|
||||||
// return int(n)
|
// return int(n)
|
||||||
// }
|
// }
|
||||||
dstLen := operands[3].Uint()
|
dstLen := operands[3].Uint(r)
|
||||||
srcLen := operands[4].Uint()
|
srcLen := operands[4].Uint(r)
|
||||||
elemSize := operands[5].Uint()
|
elemSize := operands[5].Uint(r)
|
||||||
n := srcLen
|
n := srcLen
|
||||||
if n > dstLen {
|
if n > dstLen {
|
||||||
n = dstLen
|
n = dstLen
|
||||||
@@ -374,7 +374,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, mem, r.errorAt(inst, err)
|
return nil, mem, r.errorAt(inst, err)
|
||||||
}
|
}
|
||||||
nBytes := uint32(operands[3].Uint())
|
nBytes := uint32(operands[3].Uint(r))
|
||||||
dstObj := mem.getWritable(dst.index())
|
dstObj := mem.getWritable(dst.index())
|
||||||
dstBuf := dstObj.buffer.asRawValue(r)
|
dstBuf := dstObj.buffer.asRawValue(r)
|
||||||
if mem.get(src.index()).buffer == nil {
|
if mem.get(src.index()).buffer == nil {
|
||||||
@@ -661,8 +661,8 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
// pointer into the underlying object.
|
// pointer into the underlying object.
|
||||||
var offset int64
|
var offset int64
|
||||||
for i := 1; i < len(operands); i += 2 {
|
for i := 1; i < len(operands); i += 2 {
|
||||||
index := operands[i].Int()
|
index := operands[i].Int(r)
|
||||||
elementSize := operands[i+1].Int()
|
elementSize := operands[i+1].Int(r)
|
||||||
if elementSize < 0 {
|
if elementSize < 0 {
|
||||||
// This is a struct field.
|
// This is a struct field.
|
||||||
offset += index
|
offset += index
|
||||||
@@ -677,7 +677,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
return nil, mem, r.errorAt(inst, err)
|
return nil, mem, r.errorAt(inst, err)
|
||||||
}
|
}
|
||||||
// GEP on fixed pointer value (for example, memory-mapped I/O).
|
// GEP on fixed pointer value (for example, memory-mapped I/O).
|
||||||
ptrValue := operands[0].Uint() + uint64(offset)
|
ptrValue := operands[0].Uint(r) + uint64(offset)
|
||||||
locals[inst.localIndex] = makeLiteralInt(ptrValue, int(operands[0].len(r)*8))
|
locals[inst.localIndex] = makeLiteralInt(ptrValue, int(operands[0].len(r)*8))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -739,11 +739,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
var lhs, rhs float64
|
var lhs, rhs float64
|
||||||
switch operands[0].len(r) {
|
switch operands[0].len(r) {
|
||||||
case 8:
|
case 8:
|
||||||
lhs = math.Float64frombits(operands[0].Uint())
|
lhs = math.Float64frombits(operands[0].Uint(r))
|
||||||
rhs = math.Float64frombits(operands[1].Uint())
|
rhs = math.Float64frombits(operands[1].Uint(r))
|
||||||
case 4:
|
case 4:
|
||||||
lhs = float64(math.Float32frombits(uint32(operands[0].Uint())))
|
lhs = float64(math.Float32frombits(uint32(operands[0].Uint(r))))
|
||||||
rhs = float64(math.Float32frombits(uint32(operands[1].Uint())))
|
rhs = float64(math.Float32frombits(uint32(operands[1].Uint(r))))
|
||||||
default:
|
default:
|
||||||
panic("unknown float type")
|
panic("unknown float type")
|
||||||
}
|
}
|
||||||
@@ -782,23 +782,23 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
if inst.opcode == llvm.Add {
|
if inst.opcode == llvm.Add {
|
||||||
// This likely means this is part of a
|
// This likely means this is part of a
|
||||||
// unsafe.Pointer(uintptr(ptr) + offset) pattern.
|
// unsafe.Pointer(uintptr(ptr) + offset) pattern.
|
||||||
lhsPtr, err = lhsPtr.addOffset(int64(rhs.Uint()))
|
lhsPtr, err = lhsPtr.addOffset(int64(rhs.Uint(r)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, mem, r.errorAt(inst, err)
|
return nil, mem, r.errorAt(inst, err)
|
||||||
}
|
}
|
||||||
locals[inst.localIndex] = lhsPtr
|
locals[inst.localIndex] = lhsPtr
|
||||||
} else if inst.opcode == llvm.Xor && rhs.Uint() == 0 {
|
} else if inst.opcode == llvm.Xor && rhs.Uint(r) == 0 {
|
||||||
// Special workaround for strings.noescape, see
|
// Special workaround for strings.noescape, see
|
||||||
// src/strings/builder.go in the Go source tree. This is
|
// src/strings/builder.go in the Go source tree. This is
|
||||||
// the identity operator, so we can return the input.
|
// the identity operator, so we can return the input.
|
||||||
locals[inst.localIndex] = lhs
|
locals[inst.localIndex] = lhs
|
||||||
} else if inst.opcode == llvm.And && rhs.Uint() < 8 {
|
} else if inst.opcode == llvm.And && rhs.Uint(r) < 8 {
|
||||||
// This is probably part of a pattern to get the lower bits
|
// This is probably part of a pattern to get the lower bits
|
||||||
// of a pointer for pointer tagging, like this:
|
// of a pointer for pointer tagging, like this:
|
||||||
// uintptr(unsafe.Pointer(t)) & 0b11
|
// uintptr(unsafe.Pointer(t)) & 0b11
|
||||||
// We can actually support this easily by ANDing with the
|
// We can actually support this easily by ANDing with the
|
||||||
// pointer offset.
|
// pointer offset.
|
||||||
result := uint64(lhsPtr.offset()) & rhs.Uint()
|
result := uint64(lhsPtr.offset()) & rhs.Uint(r)
|
||||||
locals[inst.localIndex] = makeLiteralInt(result, int(lhs.len(r)*8))
|
locals[inst.localIndex] = makeLiteralInt(result, int(lhs.len(r)*8))
|
||||||
} else {
|
} else {
|
||||||
// Catch-all for weird operations that should just be done
|
// Catch-all for weird operations that should just be done
|
||||||
@@ -813,31 +813,31 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
var result uint64
|
var result uint64
|
||||||
switch inst.opcode {
|
switch inst.opcode {
|
||||||
case llvm.Add:
|
case llvm.Add:
|
||||||
result = lhs.Uint() + rhs.Uint()
|
result = lhs.Uint(r) + rhs.Uint(r)
|
||||||
case llvm.Sub:
|
case llvm.Sub:
|
||||||
result = lhs.Uint() - rhs.Uint()
|
result = lhs.Uint(r) - rhs.Uint(r)
|
||||||
case llvm.Mul:
|
case llvm.Mul:
|
||||||
result = lhs.Uint() * rhs.Uint()
|
result = lhs.Uint(r) * rhs.Uint(r)
|
||||||
case llvm.UDiv:
|
case llvm.UDiv:
|
||||||
result = lhs.Uint() / rhs.Uint()
|
result = lhs.Uint(r) / rhs.Uint(r)
|
||||||
case llvm.SDiv:
|
case llvm.SDiv:
|
||||||
result = uint64(lhs.Int() / rhs.Int())
|
result = uint64(lhs.Int(r) / rhs.Int(r))
|
||||||
case llvm.URem:
|
case llvm.URem:
|
||||||
result = lhs.Uint() % rhs.Uint()
|
result = lhs.Uint(r) % rhs.Uint(r)
|
||||||
case llvm.SRem:
|
case llvm.SRem:
|
||||||
result = uint64(lhs.Int() % rhs.Int())
|
result = uint64(lhs.Int(r) % rhs.Int(r))
|
||||||
case llvm.Shl:
|
case llvm.Shl:
|
||||||
result = lhs.Uint() << rhs.Uint()
|
result = lhs.Uint(r) << rhs.Uint(r)
|
||||||
case llvm.LShr:
|
case llvm.LShr:
|
||||||
result = lhs.Uint() >> rhs.Uint()
|
result = lhs.Uint(r) >> rhs.Uint(r)
|
||||||
case llvm.AShr:
|
case llvm.AShr:
|
||||||
result = uint64(lhs.Int() >> rhs.Uint())
|
result = uint64(lhs.Int(r) >> rhs.Uint(r))
|
||||||
case llvm.And:
|
case llvm.And:
|
||||||
result = lhs.Uint() & rhs.Uint()
|
result = lhs.Uint(r) & rhs.Uint(r)
|
||||||
case llvm.Or:
|
case llvm.Or:
|
||||||
result = lhs.Uint() | rhs.Uint()
|
result = lhs.Uint(r) | rhs.Uint(r)
|
||||||
case llvm.Xor:
|
case llvm.Xor:
|
||||||
result = lhs.Uint() ^ rhs.Uint()
|
result = lhs.Uint(r) ^ rhs.Uint(r)
|
||||||
default:
|
default:
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
@@ -855,11 +855,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
// and then truncating it as necessary.
|
// and then truncating it as necessary.
|
||||||
var value uint64
|
var value uint64
|
||||||
if inst.opcode == llvm.SExt {
|
if inst.opcode == llvm.SExt {
|
||||||
value = uint64(operands[0].Int())
|
value = uint64(operands[0].Int(r))
|
||||||
} else {
|
} else {
|
||||||
value = operands[0].Uint()
|
value = operands[0].Uint(r)
|
||||||
}
|
}
|
||||||
bitwidth := operands[1].Uint()
|
bitwidth := operands[1].Uint(r)
|
||||||
if r.debug {
|
if r.debug {
|
||||||
fmt.Fprintln(os.Stderr, indent+instructionNameMap[inst.opcode]+":", value, bitwidth)
|
fmt.Fprintln(os.Stderr, indent+instructionNameMap[inst.opcode]+":", value, bitwidth)
|
||||||
}
|
}
|
||||||
@@ -868,11 +868,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
var value float64
|
var value float64
|
||||||
switch inst.opcode {
|
switch inst.opcode {
|
||||||
case llvm.SIToFP:
|
case llvm.SIToFP:
|
||||||
value = float64(operands[0].Int())
|
value = float64(operands[0].Int(r))
|
||||||
case llvm.UIToFP:
|
case llvm.UIToFP:
|
||||||
value = float64(operands[0].Uint())
|
value = float64(operands[0].Uint(r))
|
||||||
}
|
}
|
||||||
bitwidth := operands[1].Uint()
|
bitwidth := operands[1].Uint(r)
|
||||||
if r.debug {
|
if r.debug {
|
||||||
fmt.Fprintln(os.Stderr, indent+instructionNameMap[inst.opcode]+":", value, bitwidth)
|
fmt.Fprintln(os.Stderr, indent+instructionNameMap[inst.opcode]+":", value, bitwidth)
|
||||||
}
|
}
|
||||||
@@ -918,21 +918,21 @@ func (r *runner) interpretICmp(lhs, rhs value, predicate llvm.IntPredicate) bool
|
|||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
case llvm.IntUGT:
|
case llvm.IntUGT:
|
||||||
return lhs.Uint() > rhs.Uint()
|
return lhs.Uint(r) > rhs.Uint(r)
|
||||||
case llvm.IntUGE:
|
case llvm.IntUGE:
|
||||||
return lhs.Uint() >= rhs.Uint()
|
return lhs.Uint(r) >= rhs.Uint(r)
|
||||||
case llvm.IntULT:
|
case llvm.IntULT:
|
||||||
return lhs.Uint() < rhs.Uint()
|
return lhs.Uint(r) < rhs.Uint(r)
|
||||||
case llvm.IntULE:
|
case llvm.IntULE:
|
||||||
return lhs.Uint() <= rhs.Uint()
|
return lhs.Uint(r) <= rhs.Uint(r)
|
||||||
case llvm.IntSGT:
|
case llvm.IntSGT:
|
||||||
return lhs.Int() > rhs.Int()
|
return lhs.Int(r) > rhs.Int(r)
|
||||||
case llvm.IntSGE:
|
case llvm.IntSGE:
|
||||||
return lhs.Int() >= rhs.Int()
|
return lhs.Int(r) >= rhs.Int(r)
|
||||||
case llvm.IntSLT:
|
case llvm.IntSLT:
|
||||||
return lhs.Int() < rhs.Int()
|
return lhs.Int(r) < rhs.Int(r)
|
||||||
case llvm.IntSLE:
|
case llvm.IntSLE:
|
||||||
return lhs.Int() <= rhs.Int()
|
return lhs.Int(r) <= rhs.Int(r)
|
||||||
default:
|
default:
|
||||||
// _should_ be unreachable, until LLVM adds new icmp operands (unlikely)
|
// _should_ be unreachable, until LLVM adds new icmp operands (unlikely)
|
||||||
panic("interp: unsupported icmp")
|
panic("interp: unsupported icmp")
|
||||||
|
|||||||
+41
-35
@@ -361,8 +361,8 @@ type value interface {
|
|||||||
clone() value
|
clone() value
|
||||||
asPointer(*runner) (pointerValue, error)
|
asPointer(*runner) (pointerValue, error)
|
||||||
asRawValue(*runner) rawValue
|
asRawValue(*runner) rawValue
|
||||||
Uint() uint64
|
Uint(*runner) uint64
|
||||||
Int() int64
|
Int(*runner) int64
|
||||||
toLLVMValue(llvm.Type, *memoryView) (llvm.Value, error)
|
toLLVMValue(llvm.Type, *memoryView) (llvm.Value, error)
|
||||||
String() string
|
String() string
|
||||||
}
|
}
|
||||||
@@ -405,7 +405,8 @@ func (v literalValue) len(r *runner) uint32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v literalValue) String() string {
|
func (v literalValue) String() string {
|
||||||
return strconv.FormatInt(v.Int(), 10)
|
// Note: passing a nil *runner to v.Int because we know it won't use it.
|
||||||
|
return strconv.FormatInt(v.Int(nil), 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v literalValue) clone() value {
|
func (v literalValue) clone() value {
|
||||||
@@ -421,13 +422,13 @@ func (v literalValue) asRawValue(r *runner) rawValue {
|
|||||||
switch value := v.value.(type) {
|
switch value := v.value.(type) {
|
||||||
case uint64:
|
case uint64:
|
||||||
buf = make([]byte, 8)
|
buf = make([]byte, 8)
|
||||||
binary.LittleEndian.PutUint64(buf, value)
|
r.byteOrder.PutUint64(buf, value)
|
||||||
case uint32:
|
case uint32:
|
||||||
buf = make([]byte, 4)
|
buf = make([]byte, 4)
|
||||||
binary.LittleEndian.PutUint32(buf, uint32(value))
|
r.byteOrder.PutUint32(buf, uint32(value))
|
||||||
case uint16:
|
case uint16:
|
||||||
buf = make([]byte, 2)
|
buf = make([]byte, 2)
|
||||||
binary.LittleEndian.PutUint16(buf, uint16(value))
|
r.byteOrder.PutUint16(buf, uint16(value))
|
||||||
case uint8:
|
case uint8:
|
||||||
buf = []byte{uint8(value)}
|
buf = []byte{uint8(value)}
|
||||||
default:
|
default:
|
||||||
@@ -440,7 +441,7 @@ func (v literalValue) asRawValue(r *runner) rawValue {
|
|||||||
return raw
|
return raw
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v literalValue) Uint() uint64 {
|
func (v literalValue) Uint(r *runner) uint64 {
|
||||||
switch value := v.value.(type) {
|
switch value := v.value.(type) {
|
||||||
case uint64:
|
case uint64:
|
||||||
return value
|
return value
|
||||||
@@ -455,7 +456,7 @@ func (v literalValue) Uint() uint64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v literalValue) Int() int64 {
|
func (v literalValue) Int(r *runner) int64 {
|
||||||
switch value := v.value.(type) {
|
switch value := v.value.(type) {
|
||||||
case uint64:
|
case uint64:
|
||||||
return int64(value)
|
return int64(value)
|
||||||
@@ -553,11 +554,11 @@ func (v pointerValue) asRawValue(r *runner) rawValue {
|
|||||||
return rv
|
return rv
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v pointerValue) Uint() uint64 {
|
func (v pointerValue) Uint(r *runner) uint64 {
|
||||||
panic("cannot convert pointer to integer")
|
panic("cannot convert pointer to integer")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v pointerValue) Int() int64 {
|
func (v pointerValue) Int(r *runner) int64 {
|
||||||
panic("cannot convert pointer to integer")
|
panic("cannot convert pointer to integer")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -702,7 +703,12 @@ func (v rawValue) String() string {
|
|||||||
}
|
}
|
||||||
// Format as number if none of the buf is a pointer.
|
// Format as number if none of the buf is a pointer.
|
||||||
if !v.hasPointer() {
|
if !v.hasPointer() {
|
||||||
return strconv.FormatInt(v.Int(), 10)
|
// Construct a fake runner, which is little endian.
|
||||||
|
// We only use String() for debugging, so this is is good enough
|
||||||
|
// (the printed value will just be slightly wrong when debugging the
|
||||||
|
// interp package with GOOS=mips for example).
|
||||||
|
r := &runner{byteOrder: binary.LittleEndian}
|
||||||
|
return strconv.FormatInt(v.Int(r), 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "<[…" + strconv.Itoa(len(v.buf)) + "]>"
|
return "<[…" + strconv.Itoa(len(v.buf)) + "]>"
|
||||||
@@ -738,33 +744,33 @@ func (v rawValue) bytes() []byte {
|
|||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v rawValue) Uint() uint64 {
|
func (v rawValue) Uint(r *runner) uint64 {
|
||||||
buf := v.bytes()
|
buf := v.bytes()
|
||||||
|
|
||||||
switch len(v.buf) {
|
switch len(v.buf) {
|
||||||
case 1:
|
case 1:
|
||||||
return uint64(buf[0])
|
return uint64(buf[0])
|
||||||
case 2:
|
case 2:
|
||||||
return uint64(binary.LittleEndian.Uint16(buf))
|
return uint64(r.byteOrder.Uint16(buf))
|
||||||
case 4:
|
case 4:
|
||||||
return uint64(binary.LittleEndian.Uint32(buf))
|
return uint64(r.byteOrder.Uint32(buf))
|
||||||
case 8:
|
case 8:
|
||||||
return binary.LittleEndian.Uint64(buf)
|
return r.byteOrder.Uint64(buf)
|
||||||
default:
|
default:
|
||||||
panic("unknown integer size")
|
panic("unknown integer size")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v rawValue) Int() int64 {
|
func (v rawValue) Int(r *runner) int64 {
|
||||||
switch len(v.buf) {
|
switch len(v.buf) {
|
||||||
case 1:
|
case 1:
|
||||||
return int64(int8(v.Uint()))
|
return int64(int8(v.Uint(r)))
|
||||||
case 2:
|
case 2:
|
||||||
return int64(int16(v.Uint()))
|
return int64(int16(v.Uint(r)))
|
||||||
case 4:
|
case 4:
|
||||||
return int64(int32(v.Uint()))
|
return int64(int32(v.Uint(r)))
|
||||||
case 8:
|
case 8:
|
||||||
return int64(int64(v.Uint()))
|
return int64(int64(v.Uint(r)))
|
||||||
default:
|
default:
|
||||||
panic("unknown integer size")
|
panic("unknown integer size")
|
||||||
}
|
}
|
||||||
@@ -878,11 +884,11 @@ func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value,
|
|||||||
var n uint64
|
var n uint64
|
||||||
switch llvmType.IntTypeWidth() {
|
switch llvmType.IntTypeWidth() {
|
||||||
case 64:
|
case 64:
|
||||||
n = rawValue{v.buf[:8]}.Uint()
|
n = rawValue{v.buf[:8]}.Uint(mem.r)
|
||||||
case 32:
|
case 32:
|
||||||
n = rawValue{v.buf[:4]}.Uint()
|
n = rawValue{v.buf[:4]}.Uint(mem.r)
|
||||||
case 16:
|
case 16:
|
||||||
n = rawValue{v.buf[:2]}.Uint()
|
n = rawValue{v.buf[:2]}.Uint(mem.r)
|
||||||
case 8:
|
case 8:
|
||||||
n = uint64(v.buf[0])
|
n = uint64(v.buf[0])
|
||||||
case 1:
|
case 1:
|
||||||
@@ -951,7 +957,7 @@ func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value,
|
|||||||
}
|
}
|
||||||
// This is either a null pointer or a raw pointer for memory-mapped I/O
|
// This is either a null pointer or a raw pointer for memory-mapped I/O
|
||||||
// (such as 0xe000ed00).
|
// (such as 0xe000ed00).
|
||||||
ptr := rawValue{v.buf[:mem.r.pointerSize]}.Uint()
|
ptr := rawValue{v.buf[:mem.r.pointerSize]}.Uint(mem.r)
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
// Null pointer.
|
// Null pointer.
|
||||||
return llvm.ConstNull(llvmType), nil
|
return llvm.ConstNull(llvmType), nil
|
||||||
@@ -969,11 +975,11 @@ func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value,
|
|||||||
}
|
}
|
||||||
return llvm.ConstIntToPtr(ptrValue, llvmType), nil
|
return llvm.ConstIntToPtr(ptrValue, llvmType), nil
|
||||||
case llvm.DoubleTypeKind:
|
case llvm.DoubleTypeKind:
|
||||||
b := rawValue{v.buf[:8]}.Uint()
|
b := rawValue{v.buf[:8]}.Uint(mem.r)
|
||||||
f := math.Float64frombits(b)
|
f := math.Float64frombits(b)
|
||||||
return llvm.ConstFloat(llvmType, f), nil
|
return llvm.ConstFloat(llvmType, f), nil
|
||||||
case llvm.FloatTypeKind:
|
case llvm.FloatTypeKind:
|
||||||
b := uint32(rawValue{v.buf[:4]}.Uint())
|
b := uint32(rawValue{v.buf[:4]}.Uint(mem.r))
|
||||||
f := math.Float32frombits(b)
|
f := math.Float32frombits(b)
|
||||||
return llvm.ConstFloat(llvmType, float64(f)), nil
|
return llvm.ConstFloat(llvmType, float64(f)), nil
|
||||||
default:
|
default:
|
||||||
@@ -1065,19 +1071,19 @@ func (v *rawValue) set(llvmValue llvm.Value, r *runner) {
|
|||||||
switch llvmValue.Type().IntTypeWidth() {
|
switch llvmValue.Type().IntTypeWidth() {
|
||||||
case 64:
|
case 64:
|
||||||
var buf [8]byte
|
var buf [8]byte
|
||||||
binary.LittleEndian.PutUint64(buf[:], n)
|
r.byteOrder.PutUint64(buf[:], n)
|
||||||
for i, b := range buf {
|
for i, b := range buf {
|
||||||
v.buf[i] = uint64(b)
|
v.buf[i] = uint64(b)
|
||||||
}
|
}
|
||||||
case 32:
|
case 32:
|
||||||
var buf [4]byte
|
var buf [4]byte
|
||||||
binary.LittleEndian.PutUint32(buf[:], uint32(n))
|
r.byteOrder.PutUint32(buf[:], uint32(n))
|
||||||
for i, b := range buf {
|
for i, b := range buf {
|
||||||
v.buf[i] = uint64(b)
|
v.buf[i] = uint64(b)
|
||||||
}
|
}
|
||||||
case 16:
|
case 16:
|
||||||
var buf [2]byte
|
var buf [2]byte
|
||||||
binary.LittleEndian.PutUint16(buf[:], uint16(n))
|
r.byteOrder.PutUint16(buf[:], uint16(n))
|
||||||
for i, b := range buf {
|
for i, b := range buf {
|
||||||
v.buf[i] = uint64(b)
|
v.buf[i] = uint64(b)
|
||||||
}
|
}
|
||||||
@@ -1109,14 +1115,14 @@ func (v *rawValue) set(llvmValue llvm.Value, r *runner) {
|
|||||||
case llvm.DoubleTypeKind:
|
case llvm.DoubleTypeKind:
|
||||||
f, _ := llvmValue.DoubleValue()
|
f, _ := llvmValue.DoubleValue()
|
||||||
var buf [8]byte
|
var buf [8]byte
|
||||||
binary.LittleEndian.PutUint64(buf[:], math.Float64bits(f))
|
r.byteOrder.PutUint64(buf[:], math.Float64bits(f))
|
||||||
for i, b := range buf {
|
for i, b := range buf {
|
||||||
v.buf[i] = uint64(b)
|
v.buf[i] = uint64(b)
|
||||||
}
|
}
|
||||||
case llvm.FloatTypeKind:
|
case llvm.FloatTypeKind:
|
||||||
f, _ := llvmValue.DoubleValue()
|
f, _ := llvmValue.DoubleValue()
|
||||||
var buf [4]byte
|
var buf [4]byte
|
||||||
binary.LittleEndian.PutUint32(buf[:], math.Float32bits(float32(f)))
|
r.byteOrder.PutUint32(buf[:], math.Float32bits(float32(f)))
|
||||||
for i, b := range buf {
|
for i, b := range buf {
|
||||||
v.buf[i] = uint64(b)
|
v.buf[i] = uint64(b)
|
||||||
}
|
}
|
||||||
@@ -1166,11 +1172,11 @@ func (v localValue) asRawValue(r *runner) rawValue {
|
|||||||
panic("interp: localValue.asRawValue")
|
panic("interp: localValue.asRawValue")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v localValue) Uint() uint64 {
|
func (v localValue) Uint(r *runner) uint64 {
|
||||||
panic("interp: localValue.Uint")
|
panic("interp: localValue.Uint")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v localValue) Int() int64 {
|
func (v localValue) Int(r *runner) int64 {
|
||||||
panic("interp: localValue.Int")
|
panic("interp: localValue.Int")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1254,7 +1260,7 @@ func (r *runner) readObjectLayout(layoutValue value) (uint64, *big.Int) {
|
|||||||
ptr, err := layoutValue.asPointer(r)
|
ptr, err := layoutValue.asPointer(r)
|
||||||
if err == errIntegerAsPointer {
|
if err == errIntegerAsPointer {
|
||||||
// It's an integer, which means it's a small object or unknown.
|
// It's an integer, which means it's a small object or unknown.
|
||||||
layout := layoutValue.Uint()
|
layout := layoutValue.Uint(r)
|
||||||
if layout == 0 {
|
if layout == 0 {
|
||||||
// Nil pointer, which means the layout is unknown.
|
// Nil pointer, which means the layout is unknown.
|
||||||
return 0, nil
|
return 0, nil
|
||||||
@@ -1287,7 +1293,7 @@ func (r *runner) readObjectLayout(layoutValue value) (uint64, *big.Int) {
|
|||||||
|
|
||||||
// Read the object size in words and the bitmap from the global.
|
// Read the object size in words and the bitmap from the global.
|
||||||
buf := r.objects[ptr.index()].buffer.(rawValue)
|
buf := r.objects[ptr.index()].buffer.(rawValue)
|
||||||
objectSizeWords := rawValue{buf: buf.buf[:r.pointerSize]}.Uint()
|
objectSizeWords := rawValue{buf: buf.buf[:r.pointerSize]}.Uint(r)
|
||||||
rawByteValues := buf.buf[r.pointerSize:]
|
rawByteValues := buf.buf[r.pointerSize:]
|
||||||
rawBytes := make([]byte, len(rawByteValues))
|
rawBytes := make([]byte, len(rawByteValues))
|
||||||
for i, v := range rawByteValues {
|
for i, v := range rawByteValues {
|
||||||
|
|||||||
+5
-1
@@ -181,9 +181,13 @@ func TestBuild(t *testing.T) {
|
|||||||
// Run a single test for GOARCH=mips to see whether it works at all.
|
// Run a single test for GOARCH=mips to see whether it works at all.
|
||||||
// Big-endian MIPS isn't fully supported yet, but simple examples
|
// Big-endian MIPS isn't fully supported yet, but simple examples
|
||||||
// should work.
|
// should work.
|
||||||
|
// Once big-endian is fully supported, we can probably flip this
|
||||||
|
// around and do full testing of MIPS big-endian support and only do
|
||||||
|
// limited testing of MIPS little-endian (because the two are some
|
||||||
|
// similar).
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
options := optionsFromOSARCH("linux/mips/softfloat", sema)
|
options := optionsFromOSARCH("linux/mips/softfloat", sema)
|
||||||
runTest("alias.go", options, t, nil, nil)
|
runTest("map.go", options, t, nil, nil)
|
||||||
})
|
})
|
||||||
t.Run("WebAssembly", func(t *testing.T) {
|
t.Run("WebAssembly", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|||||||
Reference in New Issue
Block a user