1package transform 2 3// This file contains utilities used across transforms. 4 5import ( 6 "tinygo.org/x/go-llvm" 7) 8 9// Check whether all uses of this param as parameter to the call have the given 10// flag. In most cases, there will only be one use but a function could take the 11// same parameter twice, in which case both must have the flag. 12// A flag can be any enum flag, like "readonly". 13func hasFlag(call, param llvm.Value, kind string) bool { 14 fn := call.CalledValue() 15 if fn.IsAFunction().IsNil() { 16 // This is not a function but something else, like a function pointer. 17 return false 18 } 19 kindID := llvm.AttributeKindID(kind) 20 for i := 0; i < fn.ParamsCount(); i++ { 21 if call.Operand(i) != param { 22 // This is not the parameter we're checking. 23 continue 24 } 25 index := i + 1 // param attributes start at 1 26 attr := fn.GetEnumAttributeAtIndex(index, kindID) 27 if attr.IsNil() { 28 // At least one parameter doesn't have the flag (there may be 29 // multiple). 30 return false 31 } 32 } 33 return true 34} 35 36// isReadOnly returns true if the given value (which must be of pointer type) is 37// never stored to, and false if this cannot be proven. 38func isReadOnly(value llvm.Value) bool { 39 uses := getUses(value) 40 for _, use := range uses { 41 if !use.IsAGetElementPtrInst().IsNil() { 42 if !isReadOnly(use) { 43 return false 44 } 45 } else if !use.IsACallInst().IsNil() { 46 if !hasFlag(use, value, "readonly") { 47 return false 48 } 49 } else { 50 // Unknown instruction, might not be readonly. 51 return false 52 } 53 } 54 return true 55} 56