mirror of https://github.com/tinygo-org/tinygo.git
wasmstm32webassemblymicrocontrollerarmavrspiwasiadafruitarduinocircuitplayground-expressgpioi2cllvmmicrobitnrf51nrf52nrf52840samd21tinygo
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
121 lines
3.0 KiB
121 lines
3.0 KiB
package interp
|
|
|
|
import (
|
|
"tinygo.org/x/go-llvm"
|
|
)
|
|
|
|
// Return a list of values (actually, instructions) where this value is used as
|
|
// an operand.
|
|
func getUses(value llvm.Value) []llvm.Value {
|
|
var uses []llvm.Value
|
|
use := value.FirstUse()
|
|
for !use.IsNil() {
|
|
uses = append(uses, use.User())
|
|
use = use.NextUse()
|
|
}
|
|
return uses
|
|
}
|
|
|
|
// getStringBytes loads the byte slice of a Go string represented as a
|
|
// {ptr, len} pair.
|
|
func getStringBytes(strPtr Value, strLen llvm.Value) []byte {
|
|
if !strLen.IsConstant() {
|
|
panic("getStringBytes with a non-constant length")
|
|
}
|
|
buf := make([]byte, strLen.ZExtValue())
|
|
for i := range buf {
|
|
gep, err := strPtr.GetElementPtr([]uint32{uint32(i)})
|
|
if err != nil {
|
|
panic(err) // TODO
|
|
}
|
|
c := gep.Load()
|
|
buf[i] = byte(c.ZExtValue())
|
|
}
|
|
return buf
|
|
}
|
|
|
|
// getLLVMIndices converts an []uint32 into an []llvm.Value, for use in
|
|
// llvm.ConstGEP.
|
|
func getLLVMIndices(int32Type llvm.Type, indices []uint32) []llvm.Value {
|
|
llvmIndices := make([]llvm.Value, len(indices))
|
|
for i, index := range indices {
|
|
llvmIndices[i] = llvm.ConstInt(int32Type, uint64(index), false)
|
|
}
|
|
return llvmIndices
|
|
}
|
|
|
|
// Return true if this type is a scalar value (integer or floating point), false
|
|
// otherwise.
|
|
func isScalar(t llvm.Type) bool {
|
|
switch t.TypeKind() {
|
|
case llvm.IntegerTypeKind, llvm.FloatTypeKind, llvm.DoubleTypeKind:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// isPointerNil returns whether this is a nil pointer or not. The ok value
|
|
// indicates whether the result is certain: if it is false the result boolean is
|
|
// not valid.
|
|
func isPointerNil(v llvm.Value) (result bool, ok bool) {
|
|
if !v.IsAConstantExpr().IsNil() {
|
|
switch v.Opcode() {
|
|
case llvm.IntToPtr:
|
|
// Whether a constant inttoptr is nil is easy to
|
|
// determine.
|
|
result, ok = isZero(v.Operand(0))
|
|
if ok {
|
|
return
|
|
}
|
|
case llvm.BitCast, llvm.GetElementPtr:
|
|
// These const instructions are just a kind of wrappers for the
|
|
// underlying pointer.
|
|
return isPointerNil(v.Operand(0))
|
|
}
|
|
}
|
|
if !v.IsAConstantPointerNull().IsNil() {
|
|
// A constant pointer null is always null, of course.
|
|
return true, true
|
|
}
|
|
if !v.IsAGlobalValue().IsNil() {
|
|
// A global value is never null.
|
|
return false, true
|
|
}
|
|
return false, false // not valid
|
|
}
|
|
|
|
// isZero returns whether the value in v is the integer zero, and whether that
|
|
// can be known right now.
|
|
func isZero(v llvm.Value) (result bool, ok bool) {
|
|
if !v.IsAConstantExpr().IsNil() {
|
|
switch v.Opcode() {
|
|
case llvm.PtrToInt:
|
|
return isPointerNil(v.Operand(0))
|
|
}
|
|
}
|
|
if !v.IsAConstantInt().IsNil() {
|
|
val := v.ZExtValue()
|
|
return val == 0, true
|
|
}
|
|
return false, false // not valid
|
|
}
|
|
|
|
// unwrap returns the underlying value, with GEPs removed. This can be useful to
|
|
// get the underlying global of a GEP pointer.
|
|
func unwrap(value llvm.Value) llvm.Value {
|
|
for {
|
|
if !value.IsAConstantExpr().IsNil() {
|
|
switch value.Opcode() {
|
|
case llvm.GetElementPtr:
|
|
value = value.Operand(0)
|
|
continue
|
|
}
|
|
} else if !value.IsAGetElementPtrInst().IsNil() {
|
|
value = value.Operand(0)
|
|
continue
|
|
}
|
|
break
|
|
}
|
|
return value
|
|
}
|
|
|