github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/transform/llvm.go (about) 1 package transform 2 3 import ( 4 "reflect" 5 6 "tinygo.org/x/go-llvm" 7 ) 8 9 // Return a list of values (actually, instructions) where this value is used as 10 // an operand. 11 func getUses(value llvm.Value) []llvm.Value { 12 if value.IsNil() { 13 return nil 14 } 15 var uses []llvm.Value 16 use := value.FirstUse() 17 for !use.IsNil() { 18 uses = append(uses, use.User()) 19 use = use.NextUse() 20 } 21 return uses 22 } 23 24 // hasUses returns whether the given value has any uses. It is equivalent to 25 // getUses(value) != nil but faster. 26 func hasUses(value llvm.Value) bool { 27 if value.IsNil() { 28 return false 29 } 30 return !value.FirstUse().IsNil() 31 } 32 33 // makeGlobalArray creates a new LLVM global with the given name and integers as 34 // contents, and returns the global and initializer type. 35 // Note that it is left with the default linkage etc., you should set 36 // linkage/constant/etc properties yourself. 37 func makeGlobalArray(mod llvm.Module, bufItf interface{}, name string, elementType llvm.Type) (llvm.Type, llvm.Value) { 38 buf := reflect.ValueOf(bufItf) 39 var values []llvm.Value 40 for i := 0; i < buf.Len(); i++ { 41 ch := buf.Index(i).Uint() 42 values = append(values, llvm.ConstInt(elementType, ch, false)) 43 } 44 value := llvm.ConstArray(elementType, values) 45 global := llvm.AddGlobal(mod, value.Type(), name) 46 global.SetInitializer(value) 47 return value.Type(), global 48 } 49 50 // getGlobalBytes returns the slice contained in the array of the provided 51 // global. It can recover the bytes originally created using makeGlobalArray, if 52 // makeGlobalArray was given a byte slice. 53 // 54 // The builder parameter is only used for constant operations. 55 func getGlobalBytes(global llvm.Value, builder llvm.Builder) []byte { 56 value := global.Initializer() 57 buf := make([]byte, value.Type().ArrayLength()) 58 for i := range buf { 59 buf[i] = byte(builder.CreateExtractValue(value, i, "").ZExtValue()) 60 } 61 return buf 62 } 63 64 // replaceGlobalByteWithArray replaces a global integer type in the module with 65 // an integer array, using a GEP to make the types match. It is a convenience 66 // function used for creating reflection sidetables, for example. 67 func replaceGlobalIntWithArray(mod llvm.Module, name string, buf interface{}) llvm.Value { 68 oldGlobal := mod.NamedGlobal(name) 69 globalType, global := makeGlobalArray(mod, buf, name+".tmp", oldGlobal.GlobalValueType()) 70 gep := llvm.ConstGEP(globalType, global, []llvm.Value{ 71 llvm.ConstInt(mod.Context().Int32Type(), 0, false), 72 llvm.ConstInt(mod.Context().Int32Type(), 0, false), 73 }) 74 oldGlobal.ReplaceAllUsesWith(gep) 75 oldGlobal.EraseFromParentAsGlobal() 76 global.SetName(name) 77 return global 78 } 79 80 // stripPointerCasts strips instruction pointer casts (getelementptr and 81 // bitcast) and returns the original value without the casts. 82 func stripPointerCasts(value llvm.Value) llvm.Value { 83 if !value.IsAConstantExpr().IsNil() { 84 switch value.Opcode() { 85 case llvm.GetElementPtr, llvm.BitCast: 86 return stripPointerCasts(value.Operand(0)) 87 } 88 } 89 if !value.IsAInstruction().IsNil() { 90 switch value.InstructionOpcode() { 91 case llvm.GetElementPtr, llvm.BitCast: 92 return stripPointerCasts(value.Operand(0)) 93 } 94 } 95 return value 96 }