tinygo/transform/util.go
Ayke van Laethem 65beddafe8 compiler: move OptimizeStringToBytes to transform package
Unfortunately, while doing this I found that it doesn't actually apply
in any real-world programs (tested with `make smoketest`), apparently
because nil pointer checking messes with the functionattrs pass. I hope
to fix that after moving to LLVM 9, which has an optimization that makes
nil pointer checking easier to implement.
2019-09-22 08:25:50 +02:00

55 строки
1,5 КиБ
Go

package transform
// This file contains utilities used across transforms.
import (
"tinygo.org/x/go-llvm"
)
// Check whether all uses of this param as parameter to the call have the given
// flag. In most cases, there will only be one use but a function could take the
// same parameter twice, in which case both must have the flag.
// A flag can be any enum flag, like "readonly".
func hasFlag(call, param llvm.Value, kind string) bool {
fn := call.CalledValue()
if fn.IsAFunction().IsNil() {
// This is not a function but something else, like a function pointer.
return false
}
kindID := llvm.AttributeKindID(kind)
for i := 0; i < fn.ParamsCount(); i++ {
if call.Operand(i) != param {
// This is not the parameter we're checking.
continue
}
index := i + 1 // param attributes start at 1
attr := fn.GetEnumAttributeAtIndex(index, kindID)
if attr.IsNil() {
// At least one parameter doesn't have the flag (there may be
// multiple).
return false
}
}
return true
}
// isReadOnly returns true if the given value (which must be of pointer type) is
// never stored to, and false if this cannot be proven.
func isReadOnly(value llvm.Value) bool {
uses := getUses(value)
for _, use := range uses {
if !use.IsAGetElementPtrInst().IsNil() {
if !isReadOnly(use) {
return false
}
} else if !use.IsACallInst().IsNil() {
if !hasFlag(use, value, "readonly") {
return false
}
} else {
// Unknown instruction, might not be readonly.
return false
}
}
return true
}