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 }