github.com/aykevl/tinygo@v0.5.0/interp/utils.go (about)

     1  package interp
     2  
     3  import (
     4  	"tinygo.org/x/go-llvm"
     5  )
     6  
     7  // Return a list of values (actually, instructions) where this value is used as
     8  // an operand.
     9  func getUses(value llvm.Value) []llvm.Value {
    10  	var uses []llvm.Value
    11  	use := value.FirstUse()
    12  	for !use.IsNil() {
    13  		uses = append(uses, use.User())
    14  		use = use.NextUse()
    15  	}
    16  	return uses
    17  }
    18  
    19  // Return a zero LLVM value for any LLVM type. Setting this value as an
    20  // initializer has the same effect as setting 'zeroinitializer' on a value.
    21  // Sadly, I haven't found a way to do it directly with the Go API but this works
    22  // just fine.
    23  func getZeroValue(typ llvm.Type) llvm.Value {
    24  	switch typ.TypeKind() {
    25  	case llvm.ArrayTypeKind:
    26  		subTyp := typ.ElementType()
    27  		subVal := getZeroValue(subTyp)
    28  		vals := make([]llvm.Value, typ.ArrayLength())
    29  		for i := range vals {
    30  			vals[i] = subVal
    31  		}
    32  		return llvm.ConstArray(subTyp, vals)
    33  	case llvm.FloatTypeKind, llvm.DoubleTypeKind:
    34  		return llvm.ConstFloat(typ, 0.0)
    35  	case llvm.IntegerTypeKind:
    36  		return llvm.ConstInt(typ, 0, false)
    37  	case llvm.PointerTypeKind:
    38  		return llvm.ConstPointerNull(typ)
    39  	case llvm.StructTypeKind:
    40  		types := typ.StructElementTypes()
    41  		vals := make([]llvm.Value, len(types))
    42  		for i, subTyp := range types {
    43  			val := getZeroValue(subTyp)
    44  			vals[i] = val
    45  		}
    46  		if typ.StructName() != "" {
    47  			return llvm.ConstNamedStruct(typ, vals)
    48  		} else {
    49  			return typ.Context().ConstStruct(vals, false)
    50  		}
    51  	case llvm.VectorTypeKind:
    52  		zero := getZeroValue(typ.ElementType())
    53  		vals := make([]llvm.Value, typ.VectorSize())
    54  		for i := range vals {
    55  			vals[i] = zero
    56  		}
    57  		return llvm.ConstVector(vals, false)
    58  	default:
    59  		panic("interp: unknown LLVM type: " + typ.String())
    60  	}
    61  }
    62  
    63  // getStringBytes loads the byte slice of a Go string represented as a
    64  // {ptr, len} pair.
    65  func getStringBytes(strPtr Value, strLen llvm.Value) []byte {
    66  	if !strLen.IsConstant() {
    67  		panic("getStringBytes with a non-constant length")
    68  	}
    69  	buf := make([]byte, strLen.ZExtValue())
    70  	for i := range buf {
    71  		c := strPtr.GetElementPtr([]uint32{uint32(i)}).Load()
    72  		buf[i] = byte(c.ZExtValue())
    73  	}
    74  	return buf
    75  }
    76  
    77  // getLLVMIndices converts an []uint32 into an []llvm.Value, for use in
    78  // llvm.ConstGEP.
    79  func getLLVMIndices(int32Type llvm.Type, indices []uint32) []llvm.Value {
    80  	llvmIndices := make([]llvm.Value, len(indices))
    81  	for i, index := range indices {
    82  		llvmIndices[i] = llvm.ConstInt(int32Type, uint64(index), false)
    83  	}
    84  	return llvmIndices
    85  }
    86  
    87  // Return true if this type is a scalar value (integer or floating point), false
    88  // otherwise.
    89  func isScalar(t llvm.Type) bool {
    90  	switch t.TypeKind() {
    91  	case llvm.IntegerTypeKind, llvm.FloatTypeKind, llvm.DoubleTypeKind:
    92  		return true
    93  	default:
    94  		return false
    95  	}
    96  }