memory.go raw

   1  package interp
   2  
   3  // This file implements memory as used by interp in a reversible way.
   4  // Each new function call creates a new layer which is merged in the parent on
   5  // successful return and is thrown away when the function couldn't complete (in
   6  // which case the function call is done at runtime).
   7  // Memory is not typed, except that there is a difference between pointer and
   8  // non-pointer data. A pointer always points to an object. This implies:
   9  //   * Nil pointers are zero, and are not considered a pointer.
  10  //   * Pointers for memory-mapped I/O point to numeric pointer values, and are
  11  //     thus not considered pointers but regular values. Dereferencing them cannot be
  12  //     done in interp and results in a revert.
  13  //
  14  // Right now the memory is assumed to be little endian. This will need an update
  15  // for big endian architectures, if Moxie ever adds support for one.
  16  
  17  import (
  18  	"encoding/binary"
  19  	"errors"
  20  	"fmt"
  21  	"math"
  22  	"math/big"
  23  	"strconv"
  24  	"strings"
  25  
  26  	"tinygo.org/x/go-llvm"
  27  )
  28  
  29  // An object is a memory buffer that may be an already existing global or a
  30  // global created with runtime.alloc or the alloca instruction. If llvmGlobal is
  31  // set, that's the global for this object, otherwise it needs to be created (if
  32  // it is still reachable when the package initializer returns). The
  33  // llvmLayoutType is not necessarily a complete type: it may need to be
  34  // repeated (for example, for a slice value).
  35  //
  36  // Objects are copied in a memory view when they are stored to, to provide the
  37  // ability to roll back interpreting a function.
  38  type object struct {
  39  	llvmGlobal     llvm.Value
  40  	llvmType       llvm.Type // must match llvmGlobal.GlobalValueType() if both are set, may be unset if llvmGlobal is set
  41  	llvmLayoutType llvm.Type // LLVM type based on runtime.alloc layout parameter, if available
  42  	globalName     string    // name, if not yet created (not guaranteed to be the final name)
  43  	buffer         value     // buffer with value as given by interp, nil if external
  44  	size           uint32    // must match buffer.len(), if available
  45  	align          int       // alignment of the object (may be 0 if unknown)
  46  	constant       bool      // true if this is a constant global
  47  	marked         uint8     // 0 means unmarked, 1 means external read, 2 means external write
  48  }
  49  
  50  // clone() returns a cloned version of this object, for when an object needs to
  51  // be written to for example.
  52  func (obj object) clone() object {
  53  	if obj.buffer != nil {
  54  		obj.buffer = obj.buffer.clone()
  55  	}
  56  	return obj
  57  }
  58  
  59  // A memoryView is bound to a function activation. Loads are done from this view
  60  // or a parent view (up to the *runner if it isn't included in a view). Stores
  61  // copy the object to the current view.
  62  //
  63  // For details, see the README in the package.
  64  type memoryView struct {
  65  	r       *runner
  66  	parent  *memoryView
  67  	objects map[uint32]object
  68  
  69  	// These instructions were added to runtime.initAll while interpreting a
  70  	// function. They are stored here in a list so they can be removed if the
  71  	// execution of the function needs to be rolled back.
  72  	instructions []llvm.Value
  73  }
  74  
  75  // extend integrates the changes done by the sub-memoryView into this memory
  76  // view. This happens when a function is successfully interpreted and returns to
  77  // the parent, in which case all changed objects should be included in this
  78  // memory view.
  79  func (mv *memoryView) extend(sub memoryView) {
  80  	if mv.objects == nil && len(sub.objects) != 0 {
  81  		mv.objects = make(map[uint32]object)
  82  	}
  83  	for key, value := range sub.objects {
  84  		mv.objects[key] = value
  85  	}
  86  	mv.instructions = append(mv.instructions, sub.instructions...)
  87  }
  88  
  89  // revert undoes changes done in this memory view: it removes all instructions
  90  // created in this memoryView. Do not reuse this memoryView.
  91  func (mv *memoryView) revert() {
  92  	// Erase instructions in reverse order.
  93  	for i := len(mv.instructions) - 1; i >= 0; i-- {
  94  		llvmInst := mv.instructions[i]
  95  		if llvmInst.IsAInstruction().IsNil() {
  96  			// The IR builder will try to create constant versions of
  97  			// instructions whenever possible. If it does this, it's not an
  98  			// instruction and thus shouldn't be removed.
  99  			continue
 100  		}
 101  		llvmInst.EraseFromParentAsInstruction()
 102  	}
 103  }
 104  
 105  // markExternalLoad marks the given LLVM value as having an external read. That
 106  // means that the interpreter can still read from it, but cannot write to it as
 107  // that would mean the external read (done at runtime) reads from a state that
 108  // would not exist had the whole initialization been done at runtime.
 109  func (mv *memoryView) markExternalLoad(llvmValue llvm.Value) error {
 110  	return mv.markExternal(llvmValue, 1)
 111  }
 112  
 113  // markExternalStore marks the given LLVM value as having an external write.
 114  // This means that the interpreter can no longer read from it or write to it, as
 115  // that would happen in a different order than if all initialization were
 116  // happening at runtime.
 117  func (mv *memoryView) markExternalStore(llvmValue llvm.Value) error {
 118  	return mv.markExternal(llvmValue, 2)
 119  }
 120  
 121  // markExternal is a helper for markExternalLoad and markExternalStore, and
 122  // should not be called directly.
 123  func (mv *memoryView) markExternal(llvmValue llvm.Value, mark uint8) error {
 124  	if llvmValue.IsUndef() || llvmValue.IsNull() {
 125  		// Null and undef definitely don't contain (valid) pointers.
 126  		return nil
 127  	}
 128  	if !llvmValue.IsAInstruction().IsNil() || !llvmValue.IsAArgument().IsNil() {
 129  		// These are considered external by default, there is nothing to mark.
 130  		return nil
 131  	}
 132  
 133  	if !llvmValue.IsAGlobalValue().IsNil() {
 134  		objectIndex := mv.r.getValue(llvmValue).(pointerValue).index()
 135  		obj := mv.get(objectIndex)
 136  		if obj.marked < mark {
 137  			obj = obj.clone()
 138  			obj.marked = mark
 139  			if mv.objects == nil {
 140  				mv.objects = make(map[uint32]object)
 141  			}
 142  			mv.objects[objectIndex] = obj
 143  			if !llvmValue.IsAGlobalVariable().IsNil() {
 144  				initializer := llvmValue.Initializer()
 145  				if !initializer.IsNil() {
 146  					// Using mark '2' (which means read/write access) because
 147  					// even from an object that is only read from, the resulting
 148  					// loaded pointer can be written to.
 149  					err := mv.markExternal(initializer, 2)
 150  					if err != nil {
 151  						return err
 152  					}
 153  				}
 154  			} else {
 155  				// This is a function. Go through all instructions and mark all
 156  				// objects in there.
 157  				for bb := llvmValue.FirstBasicBlock(); !bb.IsNil(); bb = llvm.NextBasicBlock(bb) {
 158  					for inst := bb.FirstInstruction(); !inst.IsNil(); inst = llvm.NextInstruction(inst) {
 159  						opcode := inst.InstructionOpcode()
 160  						if opcode == llvm.Call {
 161  							calledValue := inst.CalledValue()
 162  							if !calledValue.IsAFunction().IsNil() {
 163  								functionName := calledValue.Name()
 164  								if functionName == "llvm.dbg.value" || strings.HasPrefix(functionName, "llvm.lifetime.") {
 165  									continue
 166  								}
 167  							}
 168  						}
 169  						if opcode == llvm.Br || opcode == llvm.Switch {
 170  							// These don't affect memory. Skipped here because
 171  							// they also have a label as operand.
 172  							continue
 173  						}
 174  						numOperands := inst.OperandsCount()
 175  						for i := 0; i < numOperands; i++ {
 176  							// Using mark '2' (which means read/write access)
 177  							// because this might be a store instruction.
 178  							err := mv.markExternal(inst.Operand(i), 2)
 179  							if err != nil {
 180  								return err
 181  							}
 182  						}
 183  					}
 184  				}
 185  			}
 186  		}
 187  	} else if !llvmValue.IsAConstantExpr().IsNil() {
 188  		switch llvmValue.Opcode() {
 189  		case llvm.IntToPtr, llvm.PtrToInt, llvm.BitCast, llvm.GetElementPtr:
 190  			err := mv.markExternal(llvmValue.Operand(0), mark)
 191  			if err != nil {
 192  				return err
 193  			}
 194  		case llvm.Add, llvm.Sub, llvm.Mul, llvm.UDiv, llvm.SDiv, llvm.URem, llvm.SRem, llvm.Shl, llvm.LShr, llvm.AShr, llvm.And, llvm.Or, llvm.Xor:
 195  			// Integer binary operators. Mark both operands.
 196  			err := mv.markExternal(llvmValue.Operand(0), mark)
 197  			if err != nil {
 198  				return err
 199  			}
 200  			err = mv.markExternal(llvmValue.Operand(1), mark)
 201  			if err != nil {
 202  				return err
 203  			}
 204  		default:
 205  			return fmt.Errorf("interp: unknown constant expression '%s'", instructionNameMap[llvmValue.Opcode()])
 206  		}
 207  	} else if !llvmValue.IsAInlineAsm().IsNil() {
 208  		// Inline assembly can modify globals but only exported globals. Let's
 209  		// hope the author knows what they're doing.
 210  	} else {
 211  		llvmType := llvmValue.Type()
 212  		switch llvmType.TypeKind() {
 213  		case llvm.IntegerTypeKind, llvm.FloatTypeKind, llvm.DoubleTypeKind:
 214  			// Nothing to do here. Integers and floats aren't pointers so don't
 215  			// need any marking.
 216  		case llvm.StructTypeKind:
 217  			numElements := llvmType.StructElementTypesCount()
 218  			for i := 0; i < numElements; i++ {
 219  				element := mv.r.builder.CreateExtractValue(llvmValue, i, "")
 220  				err := mv.markExternal(element, mark)
 221  				if err != nil {
 222  					return err
 223  				}
 224  			}
 225  		case llvm.ArrayTypeKind:
 226  			numElements := llvmType.ArrayLength()
 227  			for i := 0; i < numElements; i++ {
 228  				element := mv.r.builder.CreateExtractValue(llvmValue, i, "")
 229  				err := mv.markExternal(element, mark)
 230  				if err != nil {
 231  					return err
 232  				}
 233  			}
 234  		default:
 235  			return errors.New("interp: unknown type kind in markExternalValue")
 236  		}
 237  	}
 238  	return nil
 239  }
 240  
 241  // hasExternalLoadOrStore returns true if this object has an external load or
 242  // store. If this has happened, it is not possible for the interpreter to load
 243  // from the object or store to it without affecting the behavior of the program.
 244  func (mv *memoryView) hasExternalLoadOrStore(v pointerValue) bool {
 245  	obj := mv.get(v.index())
 246  	return obj.marked >= 1
 247  }
 248  
 249  // hasExternalStore returns true if this object has an external store. If this
 250  // is true, stores to this object are no longer allowed by the interpreter.
 251  // It returns false if it only has an external load, in which case it is still
 252  // possible for the interpreter to read from the object.
 253  func (mv *memoryView) hasExternalStore(v pointerValue) bool {
 254  	obj := mv.get(v.index())
 255  	return obj.marked >= 2 && !obj.constant
 256  }
 257  
 258  // get returns an object that can only be read from, as it may return an object
 259  // of a parent view.
 260  func (mv *memoryView) get(index uint32) object {
 261  	if obj, ok := mv.objects[index]; ok {
 262  		return obj
 263  	}
 264  	if mv.parent != nil {
 265  		return mv.parent.get(index)
 266  	}
 267  	return mv.r.objects[index]
 268  }
 269  
 270  // getWritable returns an object that can be written to.
 271  func (mv *memoryView) getWritable(index uint32) object {
 272  	if obj, ok := mv.objects[index]; ok {
 273  		// Object is already in the current memory view, so can be modified.
 274  		return obj
 275  	}
 276  	// Object is not currently in this view. Get it, and clone it for use.
 277  	obj := mv.get(index).clone()
 278  	mv.r.objects[index] = obj
 279  	return obj
 280  }
 281  
 282  // Replace the object (indicated with index) with the given object. This put is
 283  // only done at the current memory view, so that if this memory view is reverted
 284  // the object is not changed.
 285  func (mv *memoryView) put(index uint32, obj object) {
 286  	if mv.objects == nil {
 287  		mv.objects = make(map[uint32]object)
 288  	}
 289  	if checks && mv.get(index).buffer == nil {
 290  		panic("writing to external object")
 291  	}
 292  	if checks && mv.get(index).buffer.len(mv.r) != obj.buffer.len(mv.r) {
 293  		panic("put() with a differently-sized object")
 294  	}
 295  	if checks && obj.constant {
 296  		panic("interp: store to a constant")
 297  	}
 298  	mv.objects[index] = obj
 299  }
 300  
 301  // Load the value behind the given pointer. Returns nil if the pointer points to
 302  // an external global.
 303  func (mv *memoryView) load(p pointerValue, size uint32) value {
 304  	if checks && mv.hasExternalStore(p) {
 305  		panic("interp: load from object with external store")
 306  	}
 307  	obj := mv.get(p.index())
 308  	if obj.buffer == nil {
 309  		// External global, return nil.
 310  		return nil
 311  	}
 312  	if p.offset() == 0 && size == obj.size {
 313  		return obj.buffer.clone()
 314  	}
 315  	if checks && p.offset()+size > obj.size {
 316  		panic("interp: load out of bounds")
 317  	}
 318  	v := obj.buffer.asRawValue(mv.r)
 319  	loadedValue := rawValue{
 320  		buf: v.buf[p.offset() : p.offset()+size],
 321  	}
 322  	return loadedValue
 323  }
 324  
 325  // Store to the value behind the given pointer. This overwrites the value in the
 326  // memory view, so that the changed value is discarded when the memory view is
 327  // reverted. Returns true on success, false if the object to store to is
 328  // external.
 329  func (mv *memoryView) store(v value, p pointerValue) bool {
 330  	if checks && mv.hasExternalLoadOrStore(p) {
 331  		panic("interp: store to object with external load/store")
 332  	}
 333  	obj := mv.get(p.index())
 334  	if obj.buffer == nil {
 335  		// External global, return false (for a failure).
 336  		return false
 337  	}
 338  	if checks && p.offset()+v.len(mv.r) > obj.size {
 339  		panic("interp: store out of bounds")
 340  	}
 341  	if p.offset() == 0 && v.len(mv.r) == obj.buffer.len(mv.r) {
 342  		obj.buffer = v
 343  	} else {
 344  		obj = obj.clone()
 345  		buffer := obj.buffer.asRawValue(mv.r)
 346  		obj.buffer = buffer
 347  		v := v.asRawValue(mv.r)
 348  		for i := uint32(0); i < v.len(mv.r); i++ {
 349  			buffer.buf[p.offset()+i] = v.buf[i]
 350  		}
 351  	}
 352  	mv.put(p.index(), obj)
 353  	return true // success
 354  }
 355  
 356  // value is some sort of value, comparable to a LLVM constant. It can be
 357  // implemented in various ways for efficiency, but the fallback value (that all
 358  // implementations can be converted to except for localValue) is rawValue.
 359  type value interface {
 360  	// len returns the length in bytes.
 361  	len(r *runner) uint32
 362  	clone() value
 363  	asPointer(*runner) (pointerValue, error)
 364  	asRawValue(*runner) rawValue
 365  	Uint(*runner) uint64
 366  	Int(*runner) int64
 367  	toLLVMValue(llvm.Type, *memoryView) (llvm.Value, error)
 368  	String() string
 369  }
 370  
 371  // literalValue contains simple integer values that don't need to be stored in a
 372  // buffer.
 373  type literalValue struct {
 374  	value interface{}
 375  }
 376  
 377  // Make a literalValue given the number of bits.
 378  func makeLiteralInt(value uint64, bits int) literalValue {
 379  	switch bits {
 380  	case 64:
 381  		return literalValue{value}
 382  	case 32:
 383  		return literalValue{uint32(value)}
 384  	case 16:
 385  		return literalValue{uint16(value)}
 386  	case 8:
 387  		return literalValue{uint8(value)}
 388  	default:
 389  		panic("unknown integer size")
 390  	}
 391  }
 392  
 393  func (v literalValue) len(r *runner) uint32 {
 394  	switch v.value.(type) {
 395  	case uint64:
 396  		return 8
 397  	case uint32:
 398  		return 4
 399  	case uint16:
 400  		return 2
 401  	case uint8:
 402  		return 1
 403  	default:
 404  		panic("unknown value type")
 405  	}
 406  }
 407  
 408  func (v literalValue) String() string {
 409  	// Note: passing a nil *runner to v.Int because we know it won't use it.
 410  	return strconv.FormatInt(v.Int(nil), 10)
 411  }
 412  
 413  func (v literalValue) clone() value {
 414  	return v
 415  }
 416  
 417  func (v literalValue) asPointer(r *runner) (pointerValue, error) {
 418  	return pointerValue{}, errIntegerAsPointer
 419  }
 420  
 421  func (v literalValue) asRawValue(r *runner) rawValue {
 422  	var buf []byte
 423  	switch value := v.value.(type) {
 424  	case uint64:
 425  		buf = make([]byte, 8)
 426  		r.byteOrder.PutUint64(buf, value)
 427  	case uint32:
 428  		buf = make([]byte, 4)
 429  		r.byteOrder.PutUint32(buf, uint32(value))
 430  	case uint16:
 431  		buf = make([]byte, 2)
 432  		r.byteOrder.PutUint16(buf, uint16(value))
 433  	case uint8:
 434  		buf = []byte{uint8(value)}
 435  	default:
 436  		panic("unknown value type")
 437  	}
 438  	raw := newRawValue(uint32(len(buf)))
 439  	for i, b := range buf {
 440  		raw.buf[i] = uint64(b)
 441  	}
 442  	return raw
 443  }
 444  
 445  func (v literalValue) Uint(r *runner) uint64 {
 446  	switch value := v.value.(type) {
 447  	case uint64:
 448  		return value
 449  	case uint32:
 450  		return uint64(value)
 451  	case uint16:
 452  		return uint64(value)
 453  	case uint8:
 454  		return uint64(value)
 455  	default:
 456  		panic("inpterp: unknown literal type")
 457  	}
 458  }
 459  
 460  func (v literalValue) Int(r *runner) int64 {
 461  	switch value := v.value.(type) {
 462  	case uint64:
 463  		return int64(value)
 464  	case uint32:
 465  		return int64(int32(value))
 466  	case uint16:
 467  		return int64(int16(value))
 468  	case uint8:
 469  		return int64(int8(value))
 470  	default:
 471  		panic("inpterp: unknown literal type")
 472  	}
 473  }
 474  
 475  func (v literalValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value, error) {
 476  	switch llvmType.TypeKind() {
 477  	case llvm.IntegerTypeKind:
 478  		switch value := v.value.(type) {
 479  		case uint64:
 480  			return llvm.ConstInt(llvmType, value, false), nil
 481  		case uint32:
 482  			return llvm.ConstInt(llvmType, uint64(value), false), nil
 483  		case uint16:
 484  			return llvm.ConstInt(llvmType, uint64(value), false), nil
 485  		case uint8:
 486  			return llvm.ConstInt(llvmType, uint64(value), false), nil
 487  		default:
 488  			return llvm.Value{}, errors.New("interp: unknown literal type")
 489  		}
 490  	case llvm.DoubleTypeKind:
 491  		return llvm.ConstFloat(llvmType, math.Float64frombits(v.value.(uint64))), nil
 492  	case llvm.FloatTypeKind:
 493  		return llvm.ConstFloat(llvmType, float64(math.Float32frombits(v.value.(uint32)))), nil
 494  	default:
 495  		return v.asRawValue(mem.r).toLLVMValue(llvmType, mem)
 496  	}
 497  }
 498  
 499  // pointerValue contains a single pointer, with an offset into the underlying
 500  // object.
 501  type pointerValue struct {
 502  	pointer uint64 // low 32 bits are offset, high 32 bits are index
 503  }
 504  
 505  func newPointerValue(r *runner, index, offset int) pointerValue {
 506  	return pointerValue{
 507  		pointer: uint64(index)<<32 | uint64(offset),
 508  	}
 509  }
 510  
 511  func (v pointerValue) index() uint32 {
 512  	return uint32(v.pointer >> 32)
 513  }
 514  
 515  func (v pointerValue) offset() uint32 {
 516  	return uint32(v.pointer)
 517  }
 518  
 519  // addOffset essentially does a GEP operation (pointer arithmetic): it adds the
 520  // offset to the pointer. It also checks that the offset doesn't overflow the
 521  // maximum offset size (which is 4GB).
 522  func (v pointerValue) addOffset(offset int64) (pointerValue, error) {
 523  	result := pointerValue{v.pointer + uint64(offset)}
 524  	if checks && v.index() != result.index() {
 525  		return result, fmt.Errorf("interp: offset %d out of range for object %v", offset, v)
 526  	}
 527  	return result, nil
 528  }
 529  
 530  func (v pointerValue) len(r *runner) uint32 {
 531  	return r.pointerSize
 532  }
 533  
 534  func (v pointerValue) String() string {
 535  	name := strconv.Itoa(int(v.index()))
 536  	if v.offset() == 0 {
 537  		return "<" + name + ">"
 538  	}
 539  	return "<" + name + "+" + strconv.Itoa(int(v.offset())) + ">"
 540  }
 541  
 542  func (v pointerValue) clone() value {
 543  	return v
 544  }
 545  
 546  func (v pointerValue) asPointer(r *runner) (pointerValue, error) {
 547  	return v, nil
 548  }
 549  
 550  func (v pointerValue) asRawValue(r *runner) rawValue {
 551  	rv := newRawValue(r.pointerSize)
 552  	for i := range rv.buf {
 553  		rv.buf[i] = v.pointer
 554  	}
 555  	return rv
 556  }
 557  
 558  func (v pointerValue) Uint(r *runner) uint64 {
 559  	panic("cannot convert pointer to integer")
 560  }
 561  
 562  func (v pointerValue) Int(r *runner) int64 {
 563  	panic("cannot convert pointer to integer")
 564  }
 565  
 566  func (v pointerValue) equal(rhs pointerValue) bool {
 567  	return v.pointer == rhs.pointer
 568  }
 569  
 570  func (v pointerValue) llvmValue(mem *memoryView) llvm.Value {
 571  	return mem.get(v.index()).llvmGlobal
 572  }
 573  
 574  // toLLVMValue returns the LLVM value for this pointer, which may be a GEP or
 575  // bitcast. The llvm.Type parameter is optional, if omitted the pointer type may
 576  // be different than expected.
 577  func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value, error) {
 578  	// If a particular LLVM type is requested, cast to it.
 579  	if !llvmType.IsNil() && llvmType.TypeKind() != llvm.PointerTypeKind {
 580  		// The LLVM value has (or should have) the same bytes once compiled, but
 581  		// does not have the right LLVM type. This can happen for example when
 582  		// storing to a struct with a single pointer field: this pointer may
 583  		// then become the value even though the pointer should be wrapped in a
 584  		// struct.
 585  		// This can be worked around by simply converting to a raw value,
 586  		// rawValue knows how to create such structs.
 587  		return v.asRawValue(mem.r).toLLVMValue(llvmType, mem)
 588  	}
 589  
 590  	// Obtain the llvmValue, creating it if it doesn't exist yet.
 591  	llvmValue := v.llvmValue(mem)
 592  	if llvmValue.IsNil() {
 593  		// The global does not yet exist. Probably this is the result of a
 594  		// runtime.alloc.
 595  		// First allocate a new global for this object.
 596  		obj := mem.get(v.index())
 597  		alignment := obj.align
 598  		if alignment == 0 {
 599  			// Unknown alignment, perhaps from a direct call to runtime.alloc in
 600  			// the runtime. Use a conservative default instead.
 601  			alignment = mem.r.maxAlign
 602  		}
 603  		if obj.llvmType.IsNil() && obj.llvmLayoutType.IsNil() {
 604  			// Create an initializer without knowing the global type.
 605  			// This is probably the result of a runtime.alloc call.
 606  			initializer, err := obj.buffer.asRawValue(mem.r).rawLLVMValue(mem)
 607  			if err != nil {
 608  				return llvm.Value{}, err
 609  			}
 610  			globalType := initializer.Type()
 611  			llvmValue = llvm.AddGlobal(mem.r.mod, globalType, obj.globalName)
 612  			llvmValue.SetInitializer(initializer)
 613  			llvmValue.SetAlignment(alignment)
 614  			obj.llvmGlobal = llvmValue
 615  			mem.put(v.index(), obj)
 616  		} else {
 617  			// The global type is known, or at least its structure.
 618  			var globalType llvm.Type
 619  			if !obj.llvmType.IsNil() {
 620  				// The exact type is known.
 621  				globalType = obj.llvmType
 622  			} else { // !obj.llvmLayoutType.IsNil()
 623  				// The exact type isn't known, but the object layout is known.
 624  				globalType = obj.llvmLayoutType
 625  				// The layout may not span the full size of the global because
 626  				// of repetition. One example would be make([]string, 5) which
 627  				// would be 10 words in size but the layout would only be two
 628  				// words (for the string type).
 629  				typeSize := mem.r.targetData.TypeAllocSize(globalType)
 630  				if typeSize != uint64(obj.size) {
 631  					globalType = llvm.ArrayType(globalType, int(uint64(obj.size)/typeSize))
 632  				}
 633  			}
 634  			if checks && mem.r.targetData.TypeAllocSize(globalType) != uint64(obj.size) {
 635  				panic("size of the globalType isn't the same as the object size")
 636  			}
 637  			llvmValue = llvm.AddGlobal(mem.r.mod, globalType, obj.globalName)
 638  			obj.llvmGlobal = llvmValue
 639  			mem.put(v.index(), obj)
 640  
 641  			// Set the initializer for the global. Do this after creation to avoid
 642  			// infinite recursion between creating the global and creating the
 643  			// contents of the global (if the global contains itself).
 644  			initializer, err := obj.buffer.toLLVMValue(globalType, mem)
 645  			if err != nil {
 646  				return llvm.Value{}, err
 647  			}
 648  			if checks && initializer.Type() != globalType {
 649  				return llvm.Value{}, errors.New("interp: allocated value does not match allocated type")
 650  			}
 651  			llvmValue.SetInitializer(initializer)
 652  			llvmValue.SetAlignment(alignment)
 653  		}
 654  
 655  		// It should be included in r.globals because otherwise markExternal
 656  		// would consider it a new global (and would fail to mark this global as
 657  		// having an externa load/store).
 658  		mem.r.globals[llvmValue] = int(v.index())
 659  		llvmValue.SetLinkage(llvm.InternalLinkage)
 660  	}
 661  
 662  	if v.offset() != 0 {
 663  		// If there is an offset, make sure to use a GEP to index into the
 664  		// pointer.
 665  		llvmValue = llvm.ConstInBoundsGEP(mem.r.mod.Context().Int8Type(), llvmValue, []llvm.Value{
 666  			llvm.ConstInt(mem.r.mod.Context().Int32Type(), uint64(v.offset()), false),
 667  		})
 668  	}
 669  
 670  	return llvmValue, nil
 671  }
 672  
 673  // rawValue is a raw memory buffer that can store either pointers or regular
 674  // data. This is the fallback data for everything that isn't clearly a
 675  // literalValue or pointerValue.
 676  type rawValue struct {
 677  	// An integer in buf contains either pointers or bytes.
 678  	// If it is a byte, it is smaller than 256.
 679  	// If it is a pointer, the index is contained in the upper 32 bits and the
 680  	// offset is contained in the lower 32 bits.
 681  	buf []uint64
 682  }
 683  
 684  func newRawValue(size uint32) rawValue {
 685  	return rawValue{make([]uint64, size)}
 686  }
 687  
 688  func (v rawValue) len(r *runner) uint32 {
 689  	return uint32(len(v.buf))
 690  }
 691  
 692  func (v rawValue) String() string {
 693  	if len(v.buf) == 2 || len(v.buf) == 4 || len(v.buf) == 8 {
 694  		// Format as a pointer if the entire buf is this pointer.
 695  		if v.buf[0] > 255 {
 696  			isPointer := true
 697  			for _, p := range v.buf {
 698  				if p != v.buf[0] {
 699  					isPointer = false
 700  					break
 701  				}
 702  			}
 703  			if isPointer {
 704  				return pointerValue{v.buf[0]}.String()
 705  			}
 706  		}
 707  		// Format as number if none of the buf is a pointer.
 708  		if !v.hasPointer() {
 709  			// Construct a fake runner, which is little endian.
 710  			// We only use String() for debugging, so this is is good enough
 711  			// (the printed value will just be slightly wrong when debugging the
 712  			// interp package with GOOS=mips for example).
 713  			r := &runner{byteOrder: binary.LittleEndian}
 714  			return strconv.FormatInt(v.Int(r), 10)
 715  		}
 716  	}
 717  	return "<[…" + strconv.Itoa(len(v.buf)) + "]>"
 718  }
 719  
 720  func (v rawValue) clone() value {
 721  	newValue := v
 722  	newValue.buf = make([]uint64, len(v.buf))
 723  	copy(newValue.buf, v.buf)
 724  	return newValue
 725  }
 726  
 727  func (v rawValue) asPointer(r *runner) (pointerValue, error) {
 728  	if v.buf[0] <= 255 {
 729  		// Probably a null pointer or memory-mapped I/O.
 730  		return pointerValue{}, errIntegerAsPointer
 731  	}
 732  	return pointerValue{v.buf[0]}, nil
 733  }
 734  
 735  func (v rawValue) asRawValue(r *runner) rawValue {
 736  	return v
 737  }
 738  
 739  func (v rawValue) bytes() []byte {
 740  	buf := make([]byte, len(v.buf))
 741  	for i, p := range v.buf {
 742  		if p > 255 {
 743  			panic("cannot convert pointer value to byte")
 744  		}
 745  		buf[i] = byte(p)
 746  	}
 747  	return buf
 748  }
 749  
 750  func (v rawValue) Uint(r *runner) uint64 {
 751  	buf := v.bytes()
 752  
 753  	switch len(v.buf) {
 754  	case 1:
 755  		return uint64(buf[0])
 756  	case 2:
 757  		return uint64(r.byteOrder.Uint16(buf))
 758  	case 4:
 759  		return uint64(r.byteOrder.Uint32(buf))
 760  	case 8:
 761  		return r.byteOrder.Uint64(buf)
 762  	default:
 763  		panic("unknown integer size")
 764  	}
 765  }
 766  
 767  func (v rawValue) Int(r *runner) int64 {
 768  	switch len(v.buf) {
 769  	case 1:
 770  		return int64(int8(v.Uint(r)))
 771  	case 2:
 772  		return int64(int16(v.Uint(r)))
 773  	case 4:
 774  		return int64(int32(v.Uint(r)))
 775  	case 8:
 776  		return int64(int64(v.Uint(r)))
 777  	default:
 778  		panic("unknown integer size")
 779  	}
 780  }
 781  
 782  // equal returns true if (and only if) the value matches rhs.
 783  func (v rawValue) equal(rhs rawValue) bool {
 784  	if len(v.buf) != len(rhs.buf) {
 785  		panic("comparing values of different size")
 786  	}
 787  	for i, p := range v.buf {
 788  		if rhs.buf[i] != p {
 789  			return false
 790  		}
 791  	}
 792  	return true
 793  }
 794  
 795  // rawLLVMValue returns a llvm.Value for this rawValue, making up a type as it
 796  // goes. The resulting value does not have a specified type, but it will be the
 797  // same size and have the same bytes if it was created with a provided LLVM type
 798  // (through toLLVMValue).
 799  func (v rawValue) rawLLVMValue(mem *memoryView) (llvm.Value, error) {
 800  	var structFields []llvm.Value
 801  	ctx := mem.r.mod.Context()
 802  	int8Type := ctx.Int8Type()
 803  
 804  	var bytesBuf []llvm.Value
 805  	// addBytes can be called after adding to bytesBuf to flush remaining bytes
 806  	// to a new array in structFields.
 807  	addBytes := func() {
 808  		if len(bytesBuf) == 0 {
 809  			return
 810  		}
 811  		if len(bytesBuf) == 1 {
 812  			structFields = append(structFields, bytesBuf[0])
 813  		} else {
 814  			structFields = append(structFields, llvm.ConstArray(int8Type, bytesBuf))
 815  		}
 816  		bytesBuf = nil
 817  	}
 818  
 819  	// Create structFields, converting the rawValue to a LLVM value.
 820  	for i := uint32(0); i < uint32(len(v.buf)); {
 821  		if v.buf[i] > 255 {
 822  			addBytes()
 823  			field, err := pointerValue{v.buf[i]}.toLLVMValue(llvm.Type{}, mem)
 824  			if err != nil {
 825  				return llvm.Value{}, err
 826  			}
 827  			structFields = append(structFields, field)
 828  			i += mem.r.pointerSize
 829  			continue
 830  		}
 831  		val := llvm.ConstInt(int8Type, uint64(v.buf[i]), false)
 832  		bytesBuf = append(bytesBuf, val)
 833  		i++
 834  	}
 835  	addBytes()
 836  
 837  	// Return the created data.
 838  	if len(structFields) == 1 {
 839  		return structFields[0], nil
 840  	}
 841  	return ctx.ConstStruct(structFields, false), nil
 842  }
 843  
 844  func (v rawValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value, error) {
 845  	isZero := true
 846  	for _, p := range v.buf {
 847  		if p != 0 {
 848  			isZero = false
 849  			break
 850  		}
 851  	}
 852  	if isZero {
 853  		return llvm.ConstNull(llvmType), nil
 854  	}
 855  	switch llvmType.TypeKind() {
 856  	case llvm.IntegerTypeKind:
 857  		if v.buf[0] > 255 {
 858  			ptr, err := v.asPointer(mem.r)
 859  			if err != nil {
 860  				panic(err)
 861  			}
 862  			if checks && mem.r.targetData.TypeAllocSize(llvmType) != mem.r.targetData.TypeAllocSize(mem.r.dataPtrType) {
 863  				// Probably trying to serialize a pointer to a byte array,
 864  				// perhaps as a result of rawLLVMValue() in a previous interp
 865  				// run.
 866  				return llvm.Value{}, errInvalidPtrToIntSize
 867  			}
 868  			v, err := ptr.toLLVMValue(llvm.Type{}, mem)
 869  			if err != nil {
 870  				return llvm.Value{}, err
 871  			}
 872  			return llvm.ConstPtrToInt(v, llvmType), nil
 873  		}
 874  		var n uint64
 875  		switch llvmType.IntTypeWidth() {
 876  		case 64:
 877  			n = rawValue{v.buf[:8]}.Uint(mem.r)
 878  		case 32:
 879  			n = rawValue{v.buf[:4]}.Uint(mem.r)
 880  		case 16:
 881  			n = rawValue{v.buf[:2]}.Uint(mem.r)
 882  		case 8:
 883  			n = uint64(v.buf[0])
 884  		case 1:
 885  			n = uint64(v.buf[0])
 886  			if n != 0 && n != 1 {
 887  				panic("bool must be 0 or 1")
 888  			}
 889  		default:
 890  			panic("unknown integer size")
 891  		}
 892  		return llvm.ConstInt(llvmType, n, false), nil
 893  	case llvm.StructTypeKind:
 894  		fieldTypes := llvmType.StructElementTypes()
 895  		fields := make([]llvm.Value, len(fieldTypes))
 896  		for i, fieldType := range fieldTypes {
 897  			offset := mem.r.targetData.ElementOffset(llvmType, i)
 898  			field := rawValue{
 899  				buf: v.buf[offset:],
 900  			}
 901  			var err error
 902  			fields[i], err = field.toLLVMValue(fieldType, mem)
 903  			if err != nil {
 904  				return llvm.Value{}, err
 905  			}
 906  		}
 907  		if llvmType.StructName() != "" {
 908  			return llvm.ConstNamedStruct(llvmType, fields), nil
 909  		}
 910  		return llvmType.Context().ConstStruct(fields, false), nil
 911  	case llvm.ArrayTypeKind:
 912  		numElements := llvmType.ArrayLength()
 913  		childType := llvmType.ElementType()
 914  		childTypeSize := mem.r.targetData.TypeAllocSize(childType)
 915  		fields := make([]llvm.Value, numElements)
 916  		for i := range fields {
 917  			offset := i * int(childTypeSize)
 918  			field := rawValue{
 919  				buf: v.buf[offset:],
 920  			}
 921  			var err error
 922  			fields[i], err = field.toLLVMValue(childType, mem)
 923  			if err != nil {
 924  				return llvm.Value{}, err
 925  			}
 926  			if checks && fields[i].Type() != childType {
 927  				panic("child type doesn't match")
 928  			}
 929  		}
 930  		return llvm.ConstArray(childType, fields), nil
 931  	case llvm.PointerTypeKind:
 932  		if v.buf[0] > 255 {
 933  			// This is a regular pointer.
 934  			llvmValue, err := pointerValue{v.buf[0]}.toLLVMValue(llvm.Type{}, mem)
 935  			if err != nil {
 936  				return llvm.Value{}, err
 937  			}
 938  			if llvmValue.Type() != llvmType {
 939  				if llvmValue.Type().PointerAddressSpace() != llvmType.PointerAddressSpace() {
 940  					// Special case for AVR function pointers.
 941  					// Because go-llvm doesn't have addrspacecast at the moment,
 942  					// do it indirectly with a ptrtoint/inttoptr pair.
 943  					llvmValue = llvm.ConstIntToPtr(llvm.ConstPtrToInt(llvmValue, mem.r.uintptrType), llvmType)
 944  				}
 945  			}
 946  			return llvmValue, nil
 947  		}
 948  		// This is either a null pointer or a raw pointer for memory-mapped I/O
 949  		// (such as 0xe000ed00).
 950  		ptr := rawValue{v.buf[:mem.r.pointerSize]}.Uint(mem.r)
 951  		if ptr == 0 {
 952  			// Null pointer.
 953  			return llvm.ConstNull(llvmType), nil
 954  		}
 955  		var ptrValue llvm.Value // the underlying int
 956  		switch mem.r.pointerSize {
 957  		case 8:
 958  			ptrValue = llvm.ConstInt(llvmType.Context().Int64Type(), ptr, false)
 959  		case 4:
 960  			ptrValue = llvm.ConstInt(llvmType.Context().Int32Type(), ptr, false)
 961  		case 2:
 962  			ptrValue = llvm.ConstInt(llvmType.Context().Int16Type(), ptr, false)
 963  		default:
 964  			return llvm.Value{}, errors.New("interp: unknown pointer size")
 965  		}
 966  		return llvm.ConstIntToPtr(ptrValue, llvmType), nil
 967  	case llvm.DoubleTypeKind:
 968  		b := rawValue{v.buf[:8]}.Uint(mem.r)
 969  		f := math.Float64frombits(b)
 970  		return llvm.ConstFloat(llvmType, f), nil
 971  	case llvm.FloatTypeKind:
 972  		b := uint32(rawValue{v.buf[:4]}.Uint(mem.r))
 973  		f := math.Float32frombits(b)
 974  		return llvm.ConstFloat(llvmType, float64(f)), nil
 975  	default:
 976  		return llvm.Value{}, errors.New("interp: todo: raw value to LLVM value: " + llvmType.String())
 977  	}
 978  }
 979  
 980  func (v *rawValue) set(llvmValue llvm.Value, r *runner) {
 981  	if llvmValue.IsNull() {
 982  		// A zero value is common so check that first.
 983  		return
 984  	}
 985  	if !llvmValue.IsAGlobalValue().IsNil() {
 986  		ptrSize := r.pointerSize
 987  		ptr, err := r.getValue(llvmValue).asPointer(r)
 988  		if err != nil {
 989  			panic(err)
 990  		}
 991  		for i := uint32(0); i < ptrSize; i++ {
 992  			v.buf[i] = ptr.pointer
 993  		}
 994  	} else if !llvmValue.IsAConstantExpr().IsNil() {
 995  		switch llvmValue.Opcode() {
 996  		case llvm.IntToPtr, llvm.PtrToInt, llvm.BitCast:
 997  			// All these instructions effectively just reinterprets the bits
 998  			// (like a bitcast) while no bits change and keeping the same
 999  			// length, so just read its contents.
1000  			v.set(llvmValue.Operand(0), r)
1001  		case llvm.GetElementPtr:
1002  			ptr := llvmValue.Operand(0)
1003  			index := llvmValue.Operand(1)
1004  			numOperands := llvmValue.OperandsCount()
1005  			elementType := llvmValue.GEPSourceElementType()
1006  			totalOffset := r.targetData.TypeAllocSize(elementType) * index.ZExtValue()
1007  			for i := 2; i < numOperands; i++ {
1008  				indexValue := llvmValue.Operand(i)
1009  				if checks && indexValue.IsAConstantInt().IsNil() {
1010  					panic("expected const gep index to be a constant integer")
1011  				}
1012  				index := indexValue.ZExtValue()
1013  				switch elementType.TypeKind() {
1014  				case llvm.StructTypeKind:
1015  					// Indexing into a struct field.
1016  					offsetInBytes := r.targetData.ElementOffset(elementType, int(index))
1017  					totalOffset += offsetInBytes
1018  					elementType = elementType.StructElementTypes()[index]
1019  				default:
1020  					// Indexing into an array.
1021  					elementType = elementType.ElementType()
1022  					elementSize := r.targetData.TypeAllocSize(elementType)
1023  					totalOffset += index * elementSize
1024  				}
1025  			}
1026  			ptrSize := r.pointerSize
1027  			ptrValue, err := r.getValue(ptr).asPointer(r)
1028  			if err != nil {
1029  				panic(err)
1030  			}
1031  			ptrValue.pointer += totalOffset
1032  			for i := uint32(0); i < ptrSize; i++ {
1033  				v.buf[i] = ptrValue.pointer
1034  			}
1035  		case llvm.ICmp:
1036  			// Note: constant icmp isn't supported anymore in LLVM 19.
1037  			// Once we drop support for LLVM 18, this can be removed.
1038  			size := r.targetData.TypeAllocSize(llvmValue.Operand(0).Type())
1039  			lhs := newRawValue(uint32(size))
1040  			rhs := newRawValue(uint32(size))
1041  			lhs.set(llvmValue.Operand(0), r)
1042  			rhs.set(llvmValue.Operand(1), r)
1043  			if r.interpretICmp(lhs, rhs, llvmValue.IntPredicate()) {
1044  				v.buf[0] = 1 // result is true
1045  			} else {
1046  				v.buf[0] = 0 // result is false
1047  			}
1048  		default:
1049  			llvmValue.Dump()
1050  			println()
1051  			panic("unknown constant expr")
1052  		}
1053  	} else if llvmValue.IsUndef() {
1054  		// Let undef be zero, by lack of an explicit 'undef' marker.
1055  	} else {
1056  		if checks && llvmValue.IsAConstant().IsNil() {
1057  			panic("expected a constant")
1058  		}
1059  		llvmType := llvmValue.Type()
1060  		switch llvmType.TypeKind() {
1061  		case llvm.IntegerTypeKind:
1062  			n := llvmValue.ZExtValue()
1063  			switch llvmValue.Type().IntTypeWidth() {
1064  			case 64:
1065  				var buf [8]byte
1066  				r.byteOrder.PutUint64(buf[:], n)
1067  				for i, b := range buf {
1068  					v.buf[i] = uint64(b)
1069  				}
1070  			case 32:
1071  				var buf [4]byte
1072  				r.byteOrder.PutUint32(buf[:], uint32(n))
1073  				for i, b := range buf {
1074  					v.buf[i] = uint64(b)
1075  				}
1076  			case 16:
1077  				var buf [2]byte
1078  				r.byteOrder.PutUint16(buf[:], uint16(n))
1079  				for i, b := range buf {
1080  					v.buf[i] = uint64(b)
1081  				}
1082  			case 8, 1:
1083  				v.buf[0] = n
1084  			default:
1085  				panic("unknown integer size")
1086  			}
1087  		case llvm.StructTypeKind:
1088  			numElements := llvmType.StructElementTypesCount()
1089  			for i := 0; i < numElements; i++ {
1090  				offset := r.targetData.ElementOffset(llvmType, i)
1091  				field := rawValue{
1092  					buf: v.buf[offset:],
1093  				}
1094  				field.set(r.builder.CreateExtractValue(llvmValue, i, ""), r)
1095  			}
1096  		case llvm.ArrayTypeKind:
1097  			numElements := llvmType.ArrayLength()
1098  			childType := llvmType.ElementType()
1099  			childTypeSize := r.targetData.TypeAllocSize(childType)
1100  			for i := 0; i < numElements; i++ {
1101  				offset := i * int(childTypeSize)
1102  				field := rawValue{
1103  					buf: v.buf[offset:],
1104  				}
1105  				field.set(r.builder.CreateExtractValue(llvmValue, i, ""), r)
1106  			}
1107  		case llvm.DoubleTypeKind:
1108  			f, _ := llvmValue.DoubleValue()
1109  			var buf [8]byte
1110  			r.byteOrder.PutUint64(buf[:], math.Float64bits(f))
1111  			for i, b := range buf {
1112  				v.buf[i] = uint64(b)
1113  			}
1114  		case llvm.FloatTypeKind:
1115  			f, _ := llvmValue.DoubleValue()
1116  			var buf [4]byte
1117  			r.byteOrder.PutUint32(buf[:], math.Float32bits(float32(f)))
1118  			for i, b := range buf {
1119  				v.buf[i] = uint64(b)
1120  			}
1121  		default:
1122  			llvmValue.Dump()
1123  			println()
1124  			panic("unknown constant")
1125  		}
1126  	}
1127  }
1128  
1129  // hasPointer returns true if this raw value contains a pointer somewhere in the
1130  // buffer.
1131  func (v rawValue) hasPointer() bool {
1132  	for _, p := range v.buf {
1133  		if p > 255 {
1134  			return true
1135  		}
1136  	}
1137  	return false
1138  }
1139  
1140  // localValue is a special implementation of the value interface. It is a
1141  // placeholder for other values in instruction operands, and is replaced with
1142  // one of the others before executing.
1143  type localValue struct {
1144  	value llvm.Value
1145  }
1146  
1147  func (v localValue) len(r *runner) uint32 {
1148  	panic("interp: localValue.len")
1149  }
1150  
1151  func (v localValue) String() string {
1152  	return "<!>"
1153  }
1154  
1155  func (v localValue) clone() value {
1156  	panic("interp: localValue.clone()")
1157  }
1158  
1159  func (v localValue) asPointer(r *runner) (pointerValue, error) {
1160  	return pointerValue{}, errors.New("interp: localValue.asPointer called")
1161  }
1162  
1163  func (v localValue) asRawValue(r *runner) rawValue {
1164  	panic("interp: localValue.asRawValue")
1165  }
1166  
1167  func (v localValue) Uint(r *runner) uint64 {
1168  	panic("interp: localValue.Uint")
1169  }
1170  
1171  func (v localValue) Int(r *runner) int64 {
1172  	panic("interp: localValue.Int")
1173  }
1174  
1175  func (v localValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Value, error) {
1176  	return v.value, nil
1177  }
1178  
1179  func (r *runner) getValue(llvmValue llvm.Value) value {
1180  	if checks && llvmValue.IsNil() {
1181  		panic("nil llvmValue")
1182  	}
1183  	if !llvmValue.IsAGlobalValue().IsNil() {
1184  		index, ok := r.globals[llvmValue]
1185  		if !ok {
1186  			obj := object{
1187  				llvmGlobal: llvmValue,
1188  			}
1189  			index = len(r.objects)
1190  			r.globals[llvmValue] = index
1191  			r.objects = append(r.objects, obj)
1192  			if !llvmValue.IsAGlobalVariable().IsNil() {
1193  				obj.size = uint32(r.targetData.TypeAllocSize(llvmValue.GlobalValueType()))
1194  				if initializer := llvmValue.Initializer(); !initializer.IsNil() {
1195  					obj.buffer = r.getValue(initializer)
1196  					obj.constant = llvmValue.IsGlobalConstant()
1197  				}
1198  			} else if !llvmValue.IsAFunction().IsNil() {
1199  				// OK
1200  			} else {
1201  				panic("interp: unknown global value")
1202  			}
1203  			// Update the object after it has been created. This avoids an
1204  			// infinite recursion when using getValue on a global that contains
1205  			// a reference to itself.
1206  			r.objects[index] = obj
1207  		}
1208  		return newPointerValue(r, index, 0)
1209  	} else if !llvmValue.IsAConstant().IsNil() {
1210  		if !llvmValue.IsAConstantInt().IsNil() {
1211  			n := llvmValue.ZExtValue()
1212  			switch llvmValue.Type().IntTypeWidth() {
1213  			case 64:
1214  				return literalValue{n}
1215  			case 32:
1216  				return literalValue{uint32(n)}
1217  			case 16:
1218  				return literalValue{uint16(n)}
1219  			case 8, 1:
1220  				return literalValue{uint8(n)}
1221  			default:
1222  				panic("unknown integer size")
1223  			}
1224  		}
1225  		size := r.targetData.TypeAllocSize(llvmValue.Type())
1226  		v := newRawValue(uint32(size))
1227  		v.set(llvmValue, r)
1228  		return v
1229  	} else if !llvmValue.IsAInstruction().IsNil() || !llvmValue.IsAArgument().IsNil() {
1230  		return localValue{llvmValue}
1231  	} else if !llvmValue.IsAInlineAsm().IsNil() {
1232  		return localValue{llvmValue}
1233  	} else {
1234  		llvmValue.Dump()
1235  		println()
1236  		panic("unknown value")
1237  	}
1238  }
1239  
1240  // readObjectLayout reads the object layout as it is stored by the compiler. It
1241  // returns the size in the number of words and the bitmap.
1242  //
1243  // For details on this format, see src/runtime/gc_precise.go.
1244  func (r *runner) readObjectLayout(layoutValue value) (uint64, *big.Int) {
1245  	pointerSize := layoutValue.len(r)
1246  	if checks && uint64(pointerSize) != r.targetData.TypeAllocSize(r.dataPtrType) {
1247  		panic("inconsistent pointer size")
1248  	}
1249  
1250  	// The object layout can be stored in a global variable, directly as an
1251  	// integer value, or can be nil.
1252  	ptr, err := layoutValue.asPointer(r)
1253  	if err == errIntegerAsPointer {
1254  		// It's an integer, which means it's a small object or unknown.
1255  		layout := layoutValue.Uint(r)
1256  		if layout == 0 {
1257  			// Nil pointer, which means the layout is unknown.
1258  			return 0, nil
1259  		}
1260  		if layout%2 != 1 {
1261  			// Sanity check: the least significant bit must be set. This is how
1262  			// the runtime can separate pointers from integers.
1263  			panic("unexpected layout")
1264  		}
1265  
1266  		// Determine format of bitfields in the integer.
1267  		pointerBits := uint64(pointerSize * 8)
1268  		var sizeFieldBits uint64
1269  		switch pointerBits {
1270  		case 16:
1271  			sizeFieldBits = 4
1272  		case 32:
1273  			sizeFieldBits = 5
1274  		case 64:
1275  			sizeFieldBits = 6
1276  		default:
1277  			panic("unknown pointer size")
1278  		}
1279  
1280  		// Extract fields.
1281  		objectSizeWords := (layout >> 1) & (1<<sizeFieldBits - 1)
1282  		bitmap := new(big.Int).SetUint64(layout >> (1 + sizeFieldBits))
1283  		return objectSizeWords, bitmap
1284  	}
1285  
1286  	// Read the object size in words and the bitmap from the global.
1287  	buf := r.objects[ptr.index()].buffer.(rawValue)
1288  	objectSizeWords := rawValue{buf: buf.buf[:r.pointerSize]}.Uint(r)
1289  	rawByteValues := buf.buf[r.pointerSize:]
1290  	rawBytes := make([]byte, len(rawByteValues))
1291  	for i, v := range rawByteValues {
1292  		if uint64(byte(v)) != v {
1293  			panic("found pointer in data array?") // sanity check
1294  		}
1295  		rawBytes[i] = byte(v)
1296  	}
1297  	reverseBytes(rawBytes) // little-endian to big-endian
1298  	bitmap := new(big.Int).SetBytes(rawBytes)
1299  	return objectSizeWords, bitmap
1300  }
1301  
1302  // getLLVMTypeFromLayout returns the 'layout type', which is an approximation of
1303  // the real type. Pointers are in the correct location but the actual object may
1304  // have some additional repetition, for example in the buffer of a slice.
1305  func (r *runner) getLLVMTypeFromLayout(layoutValue value) llvm.Type {
1306  	objectSizeWords, bitmap := r.readObjectLayout(layoutValue)
1307  	if bitmap == nil {
1308  		// No information available.
1309  		return llvm.Type{}
1310  	}
1311  
1312  	if bitmap.BitLen() == 0 {
1313  		// There are no pointers in this object, so treat this as a raw byte
1314  		// buffer. This is important because objects without pointers may have
1315  		// lower alignment.
1316  		return r.mod.Context().Int8Type()
1317  	}
1318  
1319  	// Create the LLVM type.
1320  	pointerSize := layoutValue.len(r)
1321  	pointerAlignment := r.targetData.PrefTypeAlignment(r.dataPtrType)
1322  	var fields []llvm.Type
1323  	for i := 0; i < int(objectSizeWords); {
1324  		if bitmap.Bit(i) != 0 {
1325  			// Pointer field.
1326  			fields = append(fields, r.dataPtrType)
1327  			i += int(pointerSize / uint32(pointerAlignment))
1328  		} else {
1329  			// Byte/word field.
1330  			fields = append(fields, r.mod.Context().IntType(pointerAlignment*8))
1331  			i += 1
1332  		}
1333  	}
1334  	var llvmLayoutType llvm.Type
1335  	if len(fields) == 1 {
1336  		llvmLayoutType = fields[0]
1337  	} else {
1338  		llvmLayoutType = r.mod.Context().StructType(fields, false)
1339  	}
1340  
1341  	objectSizeBytes := objectSizeWords * uint64(pointerAlignment)
1342  	if checks && r.targetData.TypeAllocSize(llvmLayoutType) != objectSizeBytes {
1343  		panic("unexpected size") // sanity check
1344  	}
1345  	return llvmLayoutType
1346  }
1347  
1348  // Reverse a slice of bytes. From the wiki:
1349  // https://github.com/golang/go/wiki/SliceTricks#reversing
1350  func reverseBytes(buf []byte) {
1351  	for i := len(buf)/2 - 1; i >= 0; i-- {
1352  		opp := len(buf) - 1 - i
1353  		buf[i], buf[opp] = buf[opp], buf[i]
1354  	}
1355  }
1356